致电len([1,2,3])
或[1,2,3].__len__()
?
如果没有明显的差异,幕后会做些什么?
答案 0 :(得分:86)
len
是一个获取集合长度的函数。它通过调用对象的__len__
方法来工作。 __something__
属性是特殊的,通常不仅仅是满足要求,通常不应直接调用。
很久以前决定某事的长度应该是一个函数,而不是一个方法代码,推断len(a)
的含义对于初学者来说是明确的,但a.len()
不会是很清楚。当Python启动__len__
时甚至不存在,len
是一个特殊的东西,它适用于几种类型的对象。无论这种情况离开我们是否完全合理,它都会留下来。
答案 1 :(得分:61)
通常情况下,内置函数或运算符的“典型”行为是在所涉及的对象上调用(使用不同且更好的语法)合适的魔术方法(名称为__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,从不通过调用魔术方法,程序员可以免于记住哪种情况的负担。 (有时会出现错误:直到2.5,你必须拨打foo.next()
- 在2.6中,虽然仍然可以向后兼容,但你应该拨打next(foo)
,在3.*
中,魔术方法正确命名为__next__
而不是“oops-ey”next
! - )。
所以一般规则应该是永远不要直接调用魔术方法(但总是通过内置方式间接调用),除非你确切知道为什么需要这样做(例如,当你在子类中重写这样的方法时) ,如果子类需要延迟必须通过显式调用magic方法完成的超类。)
答案 2 :(得分:20)
你可以认为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)
虽然行为略有不同。 例如,在int的情况下
>>> (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()
答案 3 :(得分:4)
您可以查看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
答案 4 :(得分:-2)
嗯,len(s)
是一个内置的 Python 方法,它返回一个对象的长度。现在 __len__()
是一个特殊的方法,由 len(s)
方法内部调用以返回对象的长度。
因此,当我们调用 len(s)
方法时,s.__len__()
是在幕后实际发生的计算长度的过程。
Python len()
函数可以解释为:
def len(s):
return s.__len__()