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


Answers:


102

len是获取集合长度的函数。它通过调用对象的__len__方法来工作。__something__属性是特殊的,通常不仅仅令人眼花,乱,通常不应直接调用。

它是在很久以前的某个时刻决定的,某个东西的长度应该是一个函数,而不是方法代码,理由是len(a)初学者很清楚,但a.len()不清楚。Python启动__len__时甚至还不存在,这len是一种特殊的东西,可以处理几种类型的对象。不管情况是否如此,从总体上讲都是合理的,它将继续存在。


66

通常,内置或运算符的“典型”行为是__whatever__在所涉及的对象上调用(使用不同且更好的语法)合适的魔术方法(名称类似的方法)。内置函数或运算符通常具有“附加值”(根据所涉及的对象,它可以采用不同的路径)–在lenvs 的情况下,__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方法来完成的超类)。


我是Python的初学者用户(不是初学者那样),并且我不确定“当您看到对len内置函数的调用时,您可以确定,如果程序在那之后继续执行而不是引发异常”。我试过了:def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))它打印了I am string两次。您能再解释一下吗?
DarekNędza2014年

4
@DarekNędza与此无关,这与内建len有关。您只定义了len函数,该函数当然可以返回您想要的任何东西。OP谈到了内置len,它对所考虑的对象调用__len__特殊方法(而非函数)。
Veky

@Veky如何确定我调用的是内置函数,len而不是其他一些碰巧具有相同名称-的函数(例如在我的示例中)len。没有类似“您正在重新定义内置函数len”之类的警告。我认为,我不确定亚历克斯在回答中说了什么。
DarekNędza2014年

3
亚历克斯明确表示,如果您要调用内置函数,可以确定..._。他没有说确定要调用内置函数。但是,如果你想知道,您可以:len in vars(__builtins__).values()
Veky 2014年

1
可悲的是,这是Python中缺少对象通用基类的另一个示例。句法上下文切换一直很棘手。在某些情况下,使用下划线方法是常见的习惯用法,在其他情况下,则应使用诸如函数之类的功能来执行许多对象所共有的操作。这也很奇怪,因为许多对象没有len的语义使用。有时,对象模型更类似于C ++,厨房sinky ..
uchuugaka

28

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

2
我认为您的意思operator.methodcaller不是operator.attrgetter
Elazar

5

您可以检查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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.