Есть ли причина, по которой строки Python не имеют метода длины строки?
Я знаю, что у python есть функция len()
, которая используется для определения размера строки, но мне было интересно, почему это не метод строкового объекта.
Обновление
Хорошо, я понял, что смущенно ошибся. __len__()
- фактически метод строкового объекта. Кажется странным видеть объектно-ориентированный код в Python, используя функцию len на строковых объектах. Кроме того, также странно видеть __len__
как имя, а не только len.
Ответы
Ответ 1
Строки имеют метод длины: __len__()
Протокол в Python должен реализовать этот метод для объектов с длиной и использовать встроенную функцию len()
, которая вызывает это для вас, похоже на способ реализации __iter__()
и использовать встроенную функцию iter()
(или иметь метод, называемый за кулисами для вас) для объектов, которые являются итерабельными.
Подробнее см. Эмуляция типов контейнеров.
Здесь хорошо читается о протоколах в Python: Python и принцип наименьшего удивления
Ответ 2
Джим отвечает на этот вопрос может помочь; Я копирую его здесь. Цитируя Гвидо ван Россума:
Прежде всего, я выбрал len (x) по x.len() по причинам HCI (def __len __() появился намного позже). На самом деле есть две взаимосвязанные причины: и HCI:
(a) Для некоторых операций префиксная нотация только читается лучше, чем операции postfix - prefix (и infix!), имеют давнюю традицию в математике, которая любит записи, где визуальные эффекты помогают математику думать о проблеме. Сравните простоту, с которой мы переписываем формулу, такую как x * (a + b), в xa + xb, к неуклюжести того же самого действия, используя необработанную нотацию OO.
(b) Когда я читаю код, который говорит len (x), я знаю, что он просит длину чего-то. Это говорит мне две вещи: результат - целое число, а аргумент - это какой-то контейнер. Напротив, когда я читаю x.len(), я должен уже знать, что x - это какой-то контейнер, реализующий интерфейс или наследующий от класса, который имеет стандартный len(). Свидетельствуйте путаницу, которую мы иногда испытываем, когда класс, который не реализует сопоставление, имеет метод get() или keys() или что-то, что не является файлом, имеет метод write().
Говоря то же самое по-другому, я вижу "len" как встроенную операцию. Я ненавижу потерять это. /.../
Ответ 3
Существует метод len
:
>>> a = 'a string of some length'
>>> a.__len__()
23
>>> a.__len__
<method-wrapper '__len__' of str object at 0x02005650>
Ответ 4
Python - это прагматический язык программирования, и причины len()
, являющиеся функцией, а не метод str
, list
, dict
и т.д. являются прагматичными.
Встроенная функция len()
работает напрямую со встроенными типами: реализация CPython len()
фактически возвращает значение поля ob_size
в PyVarObject
C struct, который представляет любой встроенный в переменный размер объект в памяти. Это намного быстрее, чем вызов метода - поиск атрибутов не должен происходить. Получение количества элементов в коллекции является общей операцией и должно эффективно работать для таких базовых и разнообразных типов, как str
, list
, array.array
и т.д.
Однако для обеспечения согласованности при применении len(o)
к пользовательскому типу Python вызывает o.__len__()
как резерв. __len__
, __abs__
и все другие специальные методы, описанные в Python Data Model, позволяют легко создавать объекты, которые ведут себя как встроенные, позволяя и очень последовательные API, которые мы называем "Pythonic".
Внедряя специальные методы, ваши объекты могут поддерживать итерацию, перегружать инфиксные операторы, управлять контекстами в блоках with
и т.д. Вы можете думать о модели данных как о способе использования самого языка Python, рамки, в которой объекты, которые вы создаете, можно легко интегрировать.
Вторая причина, поддерживаемая цитатами из Guido van Rossum, вроде этого, заключается в том, что читать и писать легче len(s)
, чем s.len()
.
Обозначение len(s)
согласуется с унарными операторами с префиксным обозначением, например abs(n)
. len()
используется чаще, чем abs()
, и он заслуживает того, чтобы его было легко написать.
Также может быть историческая причина: на языке ABC, который предшествовал Python (и был очень влиятельным в его дизайне), был унарный оператор, записанный как #s
, что означало len(s)
.
Ответ 5
met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.
Ответ 6
Вы также можете сказать
>> x = 'test'
>> len(x)
4
Использование Python 2.7.3.
Ответ 7
Это не так?
>>> "abc".__len__()
3
Ответ 8
Здесь есть несколько отличных ответов, и поэтому, прежде чем я даю свои собственные, я хотел бы выделить несколько из драгоценных камней (для этого не требуется рубиновая каламбур). Я читал здесь.
- Python не является чистым языком OOP - это универсальный язык с несколькими парадигмами, который позволяет программисту использовать парадигму, которой они наиболее удобны, и/или парадигму, которая лучше всего подходит для их решения.
- Функции имеют первоклассные функции, поэтому
len
- фактически объект. С другой стороны, Ruby не имеет функций первого класса. Таким образом, объект функции len
имеет свои собственные методы, которые вы можете проверить, запустив dir(len)
.
Если вам не нравится, как это работает в вашем собственном коде, вам тривиально повторить реализацию контейнеров с использованием вашего предпочтительного метода (см. пример ниже).
>>> class List(list):
... def len(self):
... return len(self)
...
>>> class Dict(dict):
... def len(self):
... return len(self)
...
>>> class Tuple(tuple):
... def len(self):
... return len(self)
...
>>> class Set(set):
... def len(self):
... return len(self)
...
>>> my_list = List([1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'])
>>> my_dict = Dict({'key': 'value', 'site': 'stackoverflow'})
>>> my_set = Set({1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'})
>>> my_tuple = Tuple((1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'))
>>> my_containers = Tuple((my_list, my_dict, my_set, my_tuple))
>>>
>>> for container in my_containers:
... print container.len()
...
15
2
15
15