为何Python描述符仅作用于类级属性而非实例级属性?
为什么实例级属性不会触发描述符的__get__和__set__方法?
咱们先从描述符的核心触发规则说起:只有当描述符对象被定义在类的命名空间(也就是类的__dict__)中时,Python才会触发描述符协议(调用__get__、__set__)。如果描述符只是作为实例属性存在,那它就跟普通的实例对象没区别,不会触发任何描述符方法。
结合你的代码具体分析
看你定义的TestClass:
class TestClass: class_att = PropDescriptor() # 描述符存在类的__dict__里 def __init__(self): self.instance_att = PropDescriptor() # 描述符存在实例的__dict__里
- 实例属性
instance_att的行为
当你创建实例t后,self.instance_att = PropDescriptor()会把一个PropDescriptor对象直接存入t.__dict__中。后续的:
t.instance_att = 3:Python直接修改t.__dict__里的instance_att值,完全跳过类的属性查找流程,自然不会触发描述符的__set__方法。print(t.instance_att):直接从t.__dict__里取出值返回,也不会触发描述符的__get__。
这也是你输出里set instance level...和get instance level...后面没有出现描述符打印信息的原因。
- 类属性
class_att的行为class_att是定义在TestClass.__dict__里的描述符对象:
- 当执行
t.class_att =4时,因为PropDescriptor实现了__set__(属于数据描述符),Python会优先调用描述符的__set__方法,而不是在t.__dict__里新增属性。 - 当执行
print(t.class_att)时,Python先检查t.__dict__里有没有class_att,发现没有后,就去TestClass.__dict__里找,找到描述符对象后,调用它的__get__方法。
这就对应了你输出里set class level...后出现set using descriptor,get class level...后出现get using descriptor的结果。
关于你对官方文档的误解
你提到的官方文档规则:a.x会转换为调用type(a).__dict__['x'].__get__(a, type(a)),前提是实例a的__dict__里不存在x这个属性。如果实例自己的__dict__里已经有x了,Python会直接返回这个值,不会再去类的__dict__里查找,自然不会触发描述符的逻辑。
回到你的例子,instance_att一开始就存在于t.__dict__中,所以完全不会触发类层面的描述符查找流程。
内容的提问来源于stack exchange,提问作者OJNSim
相关产品推荐
相关产品推荐

