Answers:
通常,内置或运算符的“典型”行为是__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方法来完成的超类)。
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)
但是,行为略有不同。例如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()
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