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

时间:2010-03-20 00:53:24

标签: python

致电len([1,2,3])[1,2,3].__len__()

之间有什么区别吗?

如果没有明显的差异,幕后会做些什么?

5 个答案:

答案 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__()

reference