gpt4 book ai didi

python - "implicit uses of special methods always rely on the class-level binding of the special method"

转载 作者:太空狗 更新时间:2023-10-30 00:38:17 25 4
gpt4 key购买 nike

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

Per-Instance Methods

An instance can have instance-specific bindings for all attributes, including callable attributes (methods). For a method, just like for any other attribute (except those bound to overriding descriptors), an instance-specific binding hides a class-level binding: attribute lookup does not consider the class when it finds a binding directly in the instance. An instance-specific binding for a callable attribute does not perform any of the transformations detailed in “Bound and Unbound Methods” on page 110: the attribute reference returns exactly the same callable object that was earlier bound directly to the instance attribute.

However, this does not work as you might expect for per-instance bindings of the special methods that Python calls implicitly as a result of various operations, as covered in “Special Methods” on page 123. Such implicit uses of special methods always rely on the class-level binding of the special method, if any. For example:

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

具体是什么意思?

为什么会报错?

谢谢。

最佳答案

忽略所有细节,它基本上说特殊方法(如 Pythons data model 中所定义 - 通常这些方法以两个下划线开头并以两个下划线结尾,并且很少(如果有的话)直接调用)将 从不从实例中隐式使用,即使在那里定义:

n[whatever]  # will always call type(n).__getitem__(n, whatever)

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

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

文档中有一整节是关于这个的(包括基本原理):"Special method lookup" :

3.3.9. Special method lookup

For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary. That behaviour is the reason why the following code raises an exception:

>>> 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()

The rationale behind this behaviour lies with a number of special methods such as __hash__() and __repr__() that are implemented by all objects, including type objects. If the implicit lookup of these methods used the conventional lookup process, they would fail when invoked on the type object itself:

>>> 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

[...]

Bypassing the __getattribute__() machinery in this fashion provides significant scope for speed optimisations within the interpreter, at the cost of some flexibility in the handling of special methods (the special method must be set on the class object itself in order to be consistently invoked by the interpreter).

关于python - "implicit uses of special methods always rely on the class-level binding of the special method",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46054208/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com