len- функция для получения длины коллекции. Он работает, вызывая __len__метод объекта . __something__атрибуты являются особенными и обычно более обширны, чем кажется на первый взгляд, и, как правило, не должны называться напрямую.
В какой-то момент давным-давно было решено, что длина чего-либо должна быть функцией, а не кодом метода, рассуждение о том, что len(a)смысл этого будет понятен новичкам, но a.len()не так ясно. Когда начинался Python, __len__он даже не существовал и lenбыл особой вещью, которая работала с несколькими типами объектов. Независимо от того, оставляет ли нам ситуацию такая ситуация, имеет смысл, она останется здесь надолго.
Часто «типичным» поведением встроенного оператора or является вызов (с другим и более приятным синтаксисом) подходящих магических методов (с такими именами __whatever__) для задействованных объектов. Часто встроенный оператор or имеет «добавленную стоимость» (он может принимать разные пути в зависимости от задействованных объектов) - в случае lenvs __len__это просто небольшая проверка работоспособности встроенного, которого нет в магический метод:
>>> classbah(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! - ).
Таким образом, общее правило должно заключаться в том, чтобы никогда не вызывать магический метод напрямую (но всегда косвенно через встроенный), если вы точно не знаете, зачем вам это нужно (например, когда вы переопределяете такой метод в подклассе, если подкласс должен подчиняться суперклассу, что должно быть выполнено посредством явного вызова магического метода).
Я начинающий пользователь Python (не думал, что начинающий программист), и я не уверен в том, что «когда вы видите вызов встроенного len, вы уверены, что если программа продолжится после этого, а не вызовет исключение». Я пробовал это: def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))и он напечатал I am stringдважды. Вы можете объяснить это подробнее?
Дарек Нендза
4
@ DarekNędza Это не имеет ничего общего с вышеупомянутым, которое касается встроенной len. Вы только что определили свою функцию len, которая, конечно, может возвращать все, что вы хотите. OP говорил о встроенном len, который вызывает __len__специальный метод (не функцию) для рассматриваемого объекта.
Veky
@Veky Как я могу быть уверен, что вызываю встроенную функцию, а lenне какую-то другую функцию (как в моем примере) с таким же именем - len. Нет предупреждений вроде «Вы переопределяете встроенную функцию len» или чего-то подобного. На мой взгляд, я не могу быть уверен в том, что сказал Алекс в своем ответе.
Darek Nędza
3
Алекс прямо сказал, что если вы вызываете встроенный, то вы уверены ..._. Он ничего не сказал о том, что вы звоните встроенным. Но если вы хотите знать , что вы можете: len in vars(__builtins__).values().
Veky
1
К сожалению, это еще один пример отсутствия общего базового класса для объектов в Python. Синтаксическое переключение контекста всегда было чушью. В некоторых случаях это обычная идиома - использовать метод подчеркивания, в других следует использовать что-то вроде функции, чтобы делать что-то общее для многих объектов. Это также странно, потому что многие объекты не имеют смыслового использования для len. Иногда объектная модель больше похожа на C ++, кухня тонкая ..
uchuugaka
28
Вы можете думать о len () как о примерно эквиваленте
deflen(x):return x.__len__()
Одним из преимуществ является то, что он позволяет писать такие вещи, как
Однако есть немного другое поведение. Например, в случае 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()
Ответы:
len
- функция для получения длины коллекции. Он работает, вызывая__len__
метод объекта .__something__
атрибуты являются особенными и обычно более обширны, чем кажется на первый взгляд, и, как правило, не должны называться напрямую.В какой-то момент давным-давно было решено, что длина чего-либо должна быть функцией, а не кодом метода, рассуждение о том, что
len(a)
смысл этого будет понятен новичкам, ноa.len()
не так ясно. Когда начинался Python,__len__
он даже не существовал иlen
был особой вещью, которая работала с несколькими типами объектов. Независимо от того, оставляет ли нам ситуацию такая ситуация, имеет смысл, она останется здесь надолго.источник
Часто «типичным» поведением встроенного оператора or является вызов (с другим и более приятным синтаксисом) подходящих магических методов (с такими именами
__whatever__
) для задействованных объектов. Часто встроенный оператор or имеет «добавленную стоимость» (он может принимать разные пути в зависимости от задействованных объектов) - в случае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 для работы через вызовы встроенных функций и использование операторов, а не через вызовы магических методов, программисты избавлены от бремени запоминания, какой случай есть какой. (Иногда выскакивает ошибка: до версии 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(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
источник