为何为方法描述符设置__set__函数无法将其转为数据描述符?
Python描述符:动态添加__set__为何无法转为数据描述符?
问题核心
你尝试给类中的方法(本质是function实例,属于非数据描述符)动态添加__set__属性,期望将其转为数据描述符以阻止实例重写该方法,但测试中实例依然能成功赋值并覆盖,问题出在Python判断数据描述符的规则上。
根本原因
Python判断一个对象是否为数据描述符,依据的是该对象的类是否实现了__set__或__delete__方法,而非对象实例本身是否拥有这些属性。
你的测试代码中,A.d是function类的实例,尽管你给这个实例手动添加了__set__属性,但function类本身并没有定义__set__方法。因此Python依然会将其视为非数据描述符,遵循原有的属性访问优先级:实例__dict__中的值会优先于非数据描述符被返回。
当你执行a.d = "value"时,这个值直接存入了a.__dict__,后续访问a.d自然会取到这个值,而非触发描述符的__get__。
正确实现方式
要将方法转为数据描述符,必须自定义一个实现了__get__和__set__的描述符类,用该类的实例替换原有的方法:
class DataDescriptor: def __init__(self, func): self.func = func def __get__(self, instance, owner): # 模拟原方法的绑定行为 if instance is None: return self return self.func.__get__(instance, owner) def __set__(self, instance, value): print("Nothing to see here...") class A: def d(self): pass # 替换原方法为数据描述符实例 A.d = DataDescriptor(A.d) a = A() a.d = "value" # 触发__set__,打印提示 print(a.d) # 输出绑定方法,而非赋值的"value"
补充验证属性访问顺序
你理解的属性访问顺序是正确的:
- 优先查找类
__dict__中的数据描述符,调用其__get__
- 优先查找类
- 查找实例
__dict__
- 查找实例
- 查找类
__dict__中的非数据描述符,调用其__get__
- 查找类
- 最后调用
__getattr__
- 最后调用
只有当类中的属性是数据描述符时,才能跳过实例__dict__的查找,阻止实例对该属性的重写。
内容的提问来源于stack exchange,提问作者Maciej Sinicki
相关产品推荐
相关产品推荐

