"特殊方法的隐式使用总是依赖于特殊方法的类级绑定"

Tim*_*Tim 5 python

我在Nutshell中很难理解Python中的最后一部分(粗体)

每实例方法

实例可以为所有属性提供特定于实例的绑定,包括可调用属性(方法).对于方法,就像任何其他属性一样(除了那些绑定到覆盖描述符的属性),特定于实例的绑定隐藏了类级别绑定:属性查找在直接在实例中找到绑定时不考虑该类.可调用属性的特定于实例的绑定不执行第110页的"绑定和未绑定方法"中详述的任何转换:属性引用返回与先前直接绑定到实例属性的可调用对象完全相同的内容.

但是,这并不像您可能期望的那样,Python会因各种操作而隐式调用的特殊方法的每个实例绑定,如第123页的"特殊方法"中所述.特殊方法的这种隐式使用始终依赖于特殊方法的类级绑定(如果有).例如:

def fake_get_item(idx): return idx
class MyClass(object): pass
n = MyClass()
n.__getitem__ = fake_get_item
print(n[23])                      # results in:
# Traceback (most recent call last):
#   File "<stdin>", line 1, in ?
# TypeError: unindexable object
Run Code Online (Sandbox Code Playgroud)

具体是什么意思?

为什么这个例子的错误?

谢谢.

MSe*_*ert 6

忽略所有的细节,它基本上说,特殊的方法(定义蟒蛇数据模型 -通常这些都是先从两个下划线,并以两个下划线结尾的方法和很少,如果有的话,直接调用)将永远不会被使用隐含从实例,即使在那里定义:

n[whatever]  # will always call type(n).__getitem__(n, whatever)
Run Code Online (Sandbox Code Playgroud)

这与首先​​检查实例的属性查找不同:

def fake_get_item(idx): 
    return idx

class MyClass(object): 
    pass

n = MyClass()
n.__getitem__ = fake_get_item
print(n.__getitem__(23))     # works because attribute lookup checks the instance first
Run Code Online (Sandbox Code Playgroud)

文档中有一节关于此(包括基本原理):"特殊方法查找":

3.3.9.特殊方法查找

对于自定义类,只有在对象的类型上定义,而不是在对象的实例字典中,才能保证特殊方法的隐式调用正常工作.这种行为是以下代码引发异常的原因:

>>> class C:
...     pass
...
>>> c = C()
>>> c.__len__ = lambda: 5
>>> len(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'C' has no len()
Run Code Online (Sandbox Code Playgroud)

这种行为背后的基本原理在于一些特殊的方法,如__hash__()__repr__()被所有对象,包括类型对象实现.如果这些方法的隐式查找使用传统的查找过程,则在类型对象本身上调用它们时会失败:

>>> 1 .__hash__() == hash(1)
True
>>> int.__hash__() == hash(int)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor '__hash__' of 'int' object needs an argument
Run Code Online (Sandbox Code Playgroud)

[...]

__getattribute__()以这种方式绕过机器为解释器内的速度优化提供了很大的空间,代价是处理特殊方法的一些灵活性(必须在类对象本身上设置特殊方法以便由解释器一致地调用) .