Есть ли разница между звонком len([1,2,3])или [1,2,3].__len__()?
Если нет видимой разницы, что по-другому делается за кадром?
Ответы:
len- функция для получения длины коллекции. Он работает, вызывая __len__метод объекта . __something__атрибуты являются особенными и обычно более обширны, чем кажется на первый взгляд, и, как правило, не должны называться напрямую.
В какой-то момент давным-давно было решено, что длина чего-либо должна быть функцией, а не кодом метода, рассуждение о том, что len(a)смысл этого будет понятен новичкам, но a.len()не так ясно. Когда начинался Python, __len__он даже не существовал и lenбыл особой вещью, которая работала с несколькими типами объектов. Независимо от того, оставляет ли нам ситуацию такая ситуация, имеет смысл, она останется здесь надолго.
Часто «типичным» поведением встроенного оператора or является вызов (с другим и более приятным синтаксисом) подходящих магических методов (с такими именами __whatever__) для задействованных объектов. Часто встроенный оператор or имеет «добавленную стоимость» (он может принимать разные пути в зависимости от задействованных объектов) - в случае lenvs __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 для работы через вызовы встроенных функций и использование операторов, а не через вызовы магических методов, программисты избавлены от бремени запоминания, какой случай есть какой. (Иногда выскакивает ошибка: до версии 2.5 вам приходилось вызывать foo.next()- в версии 2.6, хотя это все еще работает для обратной совместимости, вы должны вызвать next(foo), и в 3.*, магический метод правильно назван __next__вместо «ой-эй» next! - ).
Таким образом, общее правило должно заключаться в том, чтобы никогда не вызывать магический метод напрямую (но всегда косвенно через встроенный), если вы точно не знаете, зачем вам это нужно (например, когда вы переопределяете такой метод в подклассе, если подкласс должен подчиняться суперклассу, что должно быть выполнено посредством явного вызова магического метода).
def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))и он напечатал I am stringдважды. Вы можете объяснить это подробнее?
__len__специальный метод (не функцию) для рассматриваемого объекта.
lenне какую-то другую функцию (как в моем примере) с таким же именем - len. Нет предупреждений вроде «Вы переопределяете встроенную функцию len» или чего-то подобного. На мой взгляд, я не могу быть уверен в том, что сказал Алекс в своем ответе.
len in vars(__builtins__).values().
Вы можете думать о 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()
operator.methodcallerвместо operator.attrgetter.
Вы можете проверить документы Pythond :
>>> 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