不保证为旧式类调用描述符。从文档:
属性访问的默认行为是从对象的字典中获取、设置或删除属性。例如,有一个以, then
a.x
开头的查找链,并继续通过
排除元类的基类。如果查找的值是定义描述符方法之一的对象,则 Python 可能会覆盖默认行为并调用描述符方法。这在优先链中发生的位置取决于定义了哪些描述符方法。请注意,仅对新样式对象或类调用描述符(如果类继承自对象或类型,则该类是新样式)。a.__dict__['x']
type(a).__dict__['x']
type(a)
所以,这里发生的事情Test.a.__set__
是永远不会被调用,你只是添加一个a
属性到t
:
In [8]: class Test:
...: def __init__(self):
...: self._a = 5
...:
...: @property
...: def a(self):
...: return self._a
...:
...: @a.setter
...: def a(self, val):
...: self._a = val
...:
In [9]: t = Test()
In [10]: vars(t)
Out[10]: {'_a': 5}
In [11]: t.a
Out[11]: 5
In [12]: t._a
Out[12]: 5
In [13]: t.a = 100
In [14]: t.a
Out[14]: 100
In [15]: t._a
Out[15]: 5
In [16]: vars(t)
Out[16]: {'_a': 5, 'a': 100}
真正应该让您感到惊讶的是,为什么要在T.a.__get__
这里工作?
答案是在 Python 2.2 中,旧式类被重新实现以使用描述符,这是一个不应该依赖的实现细节。请参阅此问题和链接问题。
最重要的是,如果您使用描述符,您应该只将它们与新型类一起使用。
请注意,如果我确实使用了新样式的类,它应该可以正常工作:
In [17]: class Test(object):
...: def __init__(self):
...: self._a = 5
...:
...: @property
...: def a(self):
...: return self._a
...:
...: @a.setter
...: def a(self, val):
...: self._a = val
...:
In [18]: t = Test()
In [19]: vars(t)
Out[19]: {'_a': 5}
In [20]: t.a = 100
In [21]: t.a
Out[21]: 100
In [22]: t._a
Out[22]: 100
In [23]: vars(t)
Out[23]: {'_a': 100}