Почему код Python использует функцию len () вместо метода длины? - PullRequest
190 голосов
/ 26 октября 2008

Я знаю, что в python есть функция len(), которая используется для определения размера строки, но мне было интересно, почему это не метод строкового объекта.

Обновление

Хорошо, я понял, что я смущенно ошибался. __len__() на самом деле является методом строкового объекта. Просто кажется странным видеть объектно-ориентированный код в Python, использующий функцию len для строковых объектов. Кроме того, также странно видеть __len__ в качестве имени вместо просто len.

Ответы [ 8 ]

170 голосов
/ 26 октября 2008

Строки имеют метод длины: __len__()

Протокол в Python состоит в том, чтобы реализовать этот метод на объектах, которые имеют длину, и использовать встроенную функцию len(), которая вызывает ее для вас, подобно тому, как вы реализуете __iter__() и используйте встроенную функцию iter() (или вызовите метод, скрытый для вас) для объектов, которые можно повторять.

См. Эмуляция типов контейнеров для получения дополнительной информации.

Вот хорошее прочтение на тему протоколов в Python: Python и принцип наименьшего удивления

84 голосов
/ 26 октября 2008

ответ Джима на этот вопрос может помочь; Я копирую это здесь. Цитируя Гвидо ван Россума:

Прежде всего, я выбрал len (x) вместо x.len () по причинам HCI (def __len __ () появилась намного позже). На самом деле есть две взаимосвязанные причины, обе HCI:

(a) Для некоторых операций префиксная нотация просто читается лучше, чем постфиксная - у префиксных (и инфиксных!) Операций есть давняя традиция в математике, которой нравятся нотации, когда визуальные элементы помогают математику думать о проблеме. Сравните простоту, с которой мы переписываем формулу, такую ​​как x * (a + b), с x a + x b с неуклюжим поступлением того же самого с использованием необработанной записи ОО.

(b) Когда я читаю код, который говорит len (x), я знаю, что он запрашивает длину чего-либо. Это говорит мне о двух вещах: результат - целое число, а аргумент - своего рода контейнер. Наоборот, когда я читаю x.len (), я уже должен знать, что x - это какой-то контейнер, реализующий интерфейс или наследующий от класса со стандартным len (). Обратите внимание на путаницу, которую мы иногда испытываем, когда класс, который не реализует отображение, имеет метод get () или keys (), или что-то, что не является файлом, имеет метод write ().

Говоря то же самое по-другому, я вижу «лен» как встроенную операцию. Я бы не хотел потерять это. / ... /

37 голосов
/ 26 октября 2008

Существует метод len:

>>> a = 'a string of some length'
>>> a.__len__()
23
>>> a.__len__
<method-wrapper '__len__' of str object at 0x02005650>
30 голосов
/ 21 апреля 2014

Python - прагматический язык программирования, и причины для len(), являющегося функцией, а не методом str, list, dict и т. Д., Прагматичны.

Встроенная функция len() имеет дело непосредственно со встроенными типами: реализация len() CPython фактически возвращает значение поля ob_size в PyVarObject C struct , которая представляет любой встроенный объект переменного размера в памяти. Это на намного быстрее, чем вызов метода - поиск атрибутов не требуется. Получение количества элементов в коллекции является обычной операцией и должно эффективно работать для таких основных и разнообразных типов, как str, list, array.array и т. Д.

Однако для обеспечения согласованности при применении len(o) к пользовательскому типу Python вызывает o.__len__() как запасной вариант. __len__, __abs__ и все другие специальные методы, задокументированные в Python Data Model , упрощают создание объектов, которые ведут себя как встроенные, предоставляя выразительные и высокосогласованные API, которые мы называем "Pythonic". ».

Реализуя специальные методы, ваши объекты могут поддерживать итерацию, инфиксные операторы перегрузки, управлять контекстами в блоках with и т. Д. Модель данных можно рассматривать как способ использования самого языка Python как каркас, в котором объекты, которые вы создаете, могут быть легко интегрированы.

Вторая причина, поддерживаемая цитатами из Гвидо ван Россума, такими как , эта , заключается в том, что легче читать и писать len(s), чем s.len().

Обозначение len(s) согласуется с унарными операторами с префиксными обозначениями, такими как abs(n). len() используется гораздо чаще, чем abs(), и заслуживает того, чтобы его было так же легко написать.

Может также быть историческая причина: в языке ABC, который предшествовал Python (и был очень влиятельным в его дизайне), был унарный оператор, записанный как #s, что означало len(s).

12 голосов
/ 26 октября 2008
met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.
3 голосов
/ 28 февраля 2017

Здесь есть несколько отличных ответов, и поэтому прежде чем дать свой, я бы хотел выделить несколько драгоценных камней (без рубиновой каламбуры), которые я прочитал здесь.

  • Python не является чистым языком ООП - это универсальный многозадачный язык, который позволяет программисту использовать наиболее удобную для него парадигму и / или ту парадигму, которая лучше всего подходит для их решения.
  • Python имеет первоклассные функции, поэтому 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
1 голос
/ 05 января 2013

Вы также можете сказать

>> x = 'test'
>> len(x)
4

Использование Python 2.7.3.

0 голосов
/ 26 октября 2008

Это не так?

>>> "abc".__len__()
3
...