len()和.__ len __()之间的区别?

调用len([1,2,3])[1,2,3].__len__()之间是否有区别? 如果没有明显的区别,幕后的做法是不同的?

len是一个获取集合长度的函数。 它通过调用对象的__len__方法来工作。 __something__属性是特殊的,通常不仅仅是满足眼睛,一般不应该直接调用。

早在某个时候就已经决定,把某个东西的长度作为一个函数而不是一个方法代码,推理len(a)的含义对初学者来说是清楚的,但是a.len()不会那么清楚。 当Python开始时, __len__甚至不存在,而len是一种特殊的东西,可以用于几种types的对象。 无论我们离开的情况是否完全合理,都留在这里。

通常情况下,内置或运算符的“典型”行为是调用(使用不同的和更好的语法)合适的魔术方法(名称类似__whatever__ )。 通常内置或运算符具有“附加价值”(根据所涉及的对象可以采用不同的path) – 对于len__len__ ,只是对缺less的内置进行了一些理智的检查从神奇的方法:

 >>> 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的调用时,你确定 ,如果程序在这之后继续,而不是引发一个exception,调用返回一个整数,非负数,小于2 ** 31 -当你看到对xxx.__len__()的调用时,你没有把握(除了代码的作者是不熟悉Python或不好的;-)。

除了简单的健全性检查和可读性外,其他内置插件还提供了更多附加值。 通过统一devise所有的Python,通过调用内置函数和使用操作符来工作,决不会通过调用魔术方法,避免程序员记住哪种情况是由哪个负担造成的。 (有时一个错误会导致:直到2.5,你必须在2.6中调用foo.next() – 虽然这对于向后兼容仍然有效,你应该调用next(foo) ,在3.* ,魔术方法是正确命名为__next__而不是“oops-ey”! – )。

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

你可以把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() 

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