Len()和.__ len__()的区别?

调用 len([1,2,3])[1,2,3].__len__()有什么区别吗?

如果没有明显的差异,那么在幕后做了哪些不同的工作?

120265 次浏览

len是一个获取集合长度的函数。它通过调用对象的 __len__方法来工作。__something__属性是特殊的,通常比我们看到的更多,一般不应该直接调用。

在很久以前的某个时候,人们就决定了取某个东西的长度应该是一个函数而不是一个方法代码,理由是 len(a)的意思对初学者来说应该很清楚,而 a.len()的意思就不那么清楚了。当 Python 刚开始运行的时候,__len__甚至还不存在,而 len是一个特殊的东西,它可以处理几种类型的对象。不管我们现在的处境是否完全合理,它都会留在这里。

可以认为 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()

通常情况下,内置或操作符的“典型”行为是对所涉及的对象调用(使用不同且更好的语法)合适的魔法方法(名称为 __whatever__的方法)。通常,内置或操作符具有“附加值”(它能够根据所涉及的对象采取不同的路径)——在 len__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内置的调用时,您就是 当然,如果程序在此之后继续运行而不是引发异常,那么该调用将返回一个整数、非负值和 <= sys.maxsize——当您看到对 xxx.__len__()的调用时,您并不确定(除非代码的作者不熟悉 Python 或者没有什么好处;)。

除了简单的健全性检查和可读性之外,其他内置程序还提供了更多的附加值。通过统一地设计所有 Python,使其通过对内置函数的调用和运算符的使用来工作,而不是通过对魔法方法的调用来工作,程序员就不必记住哪种情况是哪种情况了。(有时会出现一个错误: 在2.5之前,必须调用 foo.next()——在2.6中,虽然这仍然可以实现向后兼容性,但是应该调用 next(foo),在 3.*中,这个神奇的方法被正确地命名为 __next__,而不是“哎呀”next!-).

因此,一般的规则应该是永远不要直接调用魔法方法(但总是通过内置方法间接调用) ,除非你确切地知道为什么需要这样做(例如,当你在子类中重写这样一个方法时,如果子类需要遵从必须通过显式调用魔法方法来完成的超类)。

你可以查询 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

len(s)是一个内置的 Python 方法,它返回一个对象的长度。现在 __len__()是一个特殊的方法,len(s)方法在内部调用它来返回对象的长度。

所以,当我们调用 len(s)方法时,s.__len__()就是在幕后计算长度的实际过程。

Python len()函数可以解释为:

def len(s):
return s.__len__()

参考文献