【发布时间】:2010-03-20 00:53:24
【问题描述】:
调用len([1,2,3])或[1,2,3].__len__()有什么区别吗?
如果没有明显的区别,那么在幕后做了什么不同的事情?
【问题讨论】:
标签: python
调用len([1,2,3])或[1,2,3].__len__()有什么区别吗?
如果没有明显的区别,那么在幕后做了什么不同的事情?
【问题讨论】:
标签: python
len 是一个获取集合长度的函数。它通过调用对象的__len__ 方法来工作。 __something__ 属性比较特殊,通常不那么顺眼,一般不应该直接调用。
在很久以前的某个时候决定获取某个东西的长度应该是一个函数而不是一个方法代码,理由是len(a) 的含义对初学者来说很清楚,但a.len() 的含义就不那么清楚了。当 Python 开始时,__len__ 甚至还不存在,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;-)。
除了简单的健全性检查和可读性之外,其他内置程序还提供更多附加值。通过将所有 Python 统一设计为通过调用内置函数和使用运算符来工作,而不是通过调用魔术方法,程序员可以免于记住哪种情况是哪种情况的负担。 (有时会出现错误:在 2.5 之前,您必须调用 foo.next() -- 在 2.6 中,虽然这仍然适用于向后兼容,但您应该调用 next(foo),而在 3.* 中,魔术方法被正确命名为 @ 987654331@ 而不是“oops-ey”next!-)。
所以一般规则应该是永远不要直接调用魔法方法(但总是通过内置函数间接调用),除非你确切知道为什么需要这样做(例如,当你在子类中重写这样的方法时,如果子类需要推迟到必须通过显式调用魔术方法来完成的超类)。
【讨论】:
def len(x): return "I am a string." print(len(42)) print(len([1,2,3])),它打印了两次I am string。你能再解释一下吗?
__len__ 特殊 方法(不是函数)。
len 而不是碰巧具有相同名称的其他函数(如我的示例) - len。没有像“您正在重新定义内置函数 len”或类似的警告。在我看来,我不能确定亚历克斯在他的回答中所说的内容。
len in vars(__builtins__).values().
你可以认为 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)
但行为略有不同。 例如在整数的情况下
>>> (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()
【讨论】:
operator.methodcaller 而不是 operator.attrgetter。
您可以查看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
【讨论】:
嗯,len(s) 是一个内置的 Python 方法,它返回对象的长度。现在__len__()是一个特殊的方法,被len(s)方法内部调用,返回一个对象的长度。
所以,当我们调用len(s) 方法时,s.__len__() 是在幕后实际发生的事情来计算长度。
Python的len()函数可以解释为:
def len(s):
return s.__len__()
【讨论】: