Разница между LEN() и. лен ()?
есть ли разница между вызовом len([1,2,3])
или [1,2,3].__len__()
?
Если нет видимой разницы, что делается по-другому-за кулис?
4 ответа:
len
- Это функция для получения длины коллекции. Он работает путем вызова объекта__len__
метод.__something__
атрибуты являются особыми и обычно больше, чем кажется на первый взгляд, и, как правило, не должны вызываться напрямую.в какой-то момент было решено, что получение длины чего-то должно быть функцией, а не кодом метода, рассуждая, что
len(a)
смысл был бы понятен новичкам, ноa.len()
было бы не так ясно. Когда питон начал__len__
не даже существуют иlen
была особенная вещь, которая работала с несколькими типами объектов. Будет ли ситуации, это дает нам смысл, это здесь, чтобы остаться.
часто бывает так, что "типичное" поведение встроенного или оператора заключается в вызове (с другим и более приятным синтаксисом) подходящих магических методов (с такими именами, как
__whatever__
) на задействованных объектах. Часто встроенный или оператор имеет "добавленную стоимость" (он может принимать разные пути в зависимости от задействованных объектов) -- в случаеlen
vs__len__
, это просто немного здравомыслия проверка на встроенный, который отсутствует в волшебном методе:>>> class bah(object): ... def __len__(self): return "an inch" ... >>> bah().__len__() 'an inch' >>> len(bah()) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'str' object cannot be interpreted as an integer
когда вы смотрите звонок в
len
встроенный, ты обязательно что, если программа продолжает после этого, а не вызывает исключение, вызов вернул целое число, неотрицательное и менее 2* * 31 -- Когда вы видите вызовxxx.__len__()
, у вас нет уверенности (за исключением того, что автор кода либо не знаком с Python, либо не подходит;-).другие встроенные модули обеспечивают еще большую добавленную стоимость за простой проверки здравомыслия и удобочитаемости. Путем равномерно конструировать все из Python для работы с помощью вызовов builtins и использования операторов, никогда не вызывая магические методы, программисты избавлены от бремени запоминания того, какой случай есть. (Иногда ошибка проскальзывает: до 2.5, вы должны были позвонить
foo.next()
-- в 2.6, хотя это все еще работает для обратной совместимости, вы должны позвонитьnext(foo)
и3.*
, магический метод правильно назван__next__
вместо "ой-ей"next
!-).таким образом, общее правило должно быть никогда не вызывать магический метод напрямую (но всегда косвенно через встроенный), если вы точно не знаете, почему вам нужно это сделать (например, когда вы переопределяете такой метод в подклассе, если подкласс должен подчиняться суперклассу, который должен быть выполнен через явный вызов магического метода).
вы можете думать о len () как о примерно эквивалентном
def len(x): return x.__len__()
одним из преимуществ является то, что он позволяет писать такие вещи, как
somelist = [[1], [2, 3], [4, 5, 6]] map(len, somelist)
вместо
map(list.__len__, somelist)
или
map(operator.methodcaller('__len__'), somelist)
есть немного другое поведение, хотя. Например, в случае ints
>>> (1).__len__() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'int' object has no attribute '__len__' >>> len(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: object of type 'int' has no len()
вы можете проверить Pythond docs:
>>> class Meta(type): ... def __getattribute__(*args): ... print "Metaclass getattribute invoked" ... return type.__getattribute__(*args) ... >>> class C(object): ... __metaclass__ = Meta ... def __len__(self): ... return 10 ... def __getattribute__(*args): ... print "Class getattribute invoked" ... return object.__getattribute__(*args) ... >>> c = C() >>> c.__len__() # Explicit lookup via instance Class getattribute invoked 10 >>> type(c).__len__(c) # Explicit lookup via type Metaclass getattribute invoked 10 >>> len(c) # Implicit lookup 10