我尝试更彻底地理解描述符和显式属性名称查找顺序。
我读了descriptor howto它声明如下:
The details of invocation depend on whether obj is an object or a class:
...
For classes, the machinery is intype.__getattribute__
() which transformsB.x
intoB.__dict__['x'].__get__(None, B)
我在 __class_
_ 上测试它,因为它是 object
的数据描述符
In [47]: object.__class__
Out[47]: type
因此,它按预期返回 type
,因为 type
类创建了所有类,包括 object
类。基于'descriptor howto',object.__class__
变成了object.__dict__['__class__'].__get__(None, object)
.
但是,当我运行它时,输出是描述符本身,而不是 type
In [48]: object.__dict__['__class__'].__get__(None, object)
Out[48]: <attribute '__class__' of 'object' objects>
我猜它会返回描述符本身,因为在这个 __get__
内部有一些类似的代码:
if instance is None:
return self
所以,我理解了从类调用时返回描述符本身的原因。让我困惑的是不同的输出
当它说“B.x
into B.__dict__['x'].__get__(None, B)
'时,我希望输出是相同的。它们为什么不同?
最佳答案
描述符操作方法是一种简化。它掩盖了元类之类的东西,以及类是对象的事实。类是对象,它们通过“对象式”和“类式”属性查找和描述符处理。 (如果您想独立验证,可以在 type_getattro
中找到实现。)
查找 object.__class__
不只是通过 object.__mro__
;它还会查看 type(object).__mro__
.在 type(object).__mro__
中找到的描述符使用“对象式”描述符处理,将类视为其元类的实例,而描述符在 object.__mro__
中找到使用“类风格”描述符处理。
当你查找object.__class__
时, Python 搜索 type(object).__mro__
.自 object
在type(object).__mro__
, 此搜索找到 object.__dict__['__class__']
.自 object.__dict__['__class__']
是一个数据描述符(它有一个 __set__
),这优先于通过 object.__mro__
的搜索.因此,治疗object
作为 object
的实例而不是作为一个类,Python 执行
descr.__get__(object, type(object))
代替
descr.__get__(None, object)
和 __get__
调用返回 type(object)
,即 type
.
您的手册 descr.__get__(None, object)
来电请客object
作为类而不是 object
的实例.以这种方式调用,描述符返回自身。
为了证明__class__
这里不是特例,我们可以创建我们的 own 类,它是它自己的一个实例,就像 object
是:
class DummyMeta(type):
pass
class SelfMeta(type, metaclass=DummyMeta):
@property
def x(self):
return 3
SelfMeta.__class__ = SelfMeta
print(SelfMeta.x)
print(SelfMeta.__dict__['x'].__get__(None, SelfMeta))
print(SelfMeta.__dict__['x'].__get__(SelfMeta, type(SelfMeta)))
输出:
3
<property object at 0x2aff9f04c5e8>
3
就像 object.__class__
一样,“对象式”描述符处理也发生在这里。 (此外,如果您想知道,即使您不编写 setter,属性也是数据描述符。)
关于python - 对象类的描述符 __class__ 的 __get__ 未按预期返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55312116/