Python中为什么描述符不能定义为实例属性?

如题,为什么实例属性的描述符不会自动调用描述符协议的 get()…这些方法?

只能在类属性中定义描述符?
Python中为什么描述符不能定义为实例属性?

6 回复

说一下我的理解。python 文档里说,实例对象调用描述符的过程是这样的:调用 b.x 时,实际是转化为 type(b).dict[‘x’].get(b, type(b))执行的。如果 x 是实例属性的话,那肯定在类的 dict 里找不到了,也就无法自动进行调用了。


因为描述符协议(__get__, __set__, __delete__)的触发依赖于类层面的属性访问。当你通过实例.属性访问时,Python解释器会先在实例的__dict__中查找,如果没找到,才会去类的__dict__中查找。如果此时在类里找到了一个实现了描述符协议的对象,协议方法才会被调用。

如果把描述符对象直接赋值给实例属性(比如在__init__里写self.descriptor = DescriptorInstance()),那么这个描述符对象就只是安静地躺在实例的__dict__里,成了一个普通的对象。通过实例.属性访问它时,Python直接在实例__dict__里找到了它,查找过程就此结束,根本不会去触发它内部的__get____set__方法。

核心就一点:描述符必须作为类属性,才能被Python的解释器机制正确识别和调用。

简单说就是,放错地方了,机制不认。

https://docs.python.org/3/howto/descriptor.html#invoking-descriptors

For objects, the machinery is in object.getattribute() which transforms b.x into type(b).dict[‘x’].get(b, type(b)). The implementation works through a precedence chain that gives data descriptors priority over instance variables, instance variables priority over non-data descriptors, and assigns lowest priority to getattr() if provided. The full C implementation can be found in PyObject_GenericGetAttr() in Objects/object.c.

For classes, the machinery is in type.getattribute() which transforms B.x into B.dict[‘x’].get(None, B).

感谢

我的疑问就是转换这一步,为什么要为转换为 type(b).dict[‘x’].get(b, type(b)) ,而不是直接调用 b.dict[‘x’].get(b, type(b))

把 x 定义为实例属性,肯定可以在 b 的 dict 中找到,但是输出 b.x 时却不会触发 b.dict[‘x’].get(b, type(b)) 这样的调用

我知道这样的转换是在 object.getattribute()/type .getattribute() 写好的,只是想不明白为什么这样,有点卡壳

如果是为了数据描述符和非数据描述符的优先级,那区分它们有什么意义吗?

你们有什么想法,可以点一点我,感谢

或许我应该去看看 PEP

先想想对象和类调用时,为什么传给 get 的参数要不一样。再想想类也是对象,如果要满足你的设定,get 的参数就得一样了。

谢谢

回到顶部