问题:len()和.__ len __()之间的区别?
呼叫len([1,2,3])
或之间有什么区别[1,2,3].__len__()
?
如果没有明显的差异,那么幕后的操作又有什么不同?
回答 0
len
是获取集合长度的函数。它通过调用对象的__len__
方法来工作。__something__
属性是特殊的,通常不仅仅令人眼花,乱,通常不应直接调用。
它是在很久以前的某个时刻决定的,某个东西的长度应该是一个函数,而不是方法代码,理由是len(a)
初学者很清楚,但a.len()
不清楚。Python启动__len__
时甚至还不存在,这len
是一种特殊的东西,可以处理几种类型的对象。不管情况是否如此,从总体上讲都是合理的,它将继续存在。
回答 1
通常,内置或运算符的“典型”行为是__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.*
,magic方法已正确命名,__next__
而不是“ oops-ey” next
!- )。
因此,一般的规则应该是永远不要直接调用魔术方法(而总是通过内置方法间接调用),除非您确切知道为什么需要这样做(例如,当您在子类中覆盖此类方法时,如果子类需要遵循必须通过显式调用magic方法来完成的超类)。
回答 2
您可以认为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
您可以检查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