__set__
三个特殊方法
- __set __(self, obj, type=None):在设置属性时将调用这一方法;
- __get __(self, obj, value):在读取属性时将调用这一方法;
- __delete __(self, obj):对属性调用 del 时将调用这一方法。
class RevealAccess:
def __init__(self, init_val=None, name='var'):
self.val = init_val
self.name = name
def __get__(self, obj, obj_type):
print("Retrieving", self.name)
return self.val
def __set__(self, obj, val):
print("updating", self.name)
self.val = val
class MyClass:
x = RevealAccess(10, 'var "x"')
y = 5
m = MyClass()
print(m.x)
m.x = 20
print(m.x)
print(m.y)
### 运行结果
Retrieving var "x"
10
updating var "x"
Retrieving var "x"
20
5
查找属性顺序
在每次查找属性时,描述符协议中的方法都由类对象的特殊方法 getattribute() 调用(注意不要和 getattr() 弄混)。也就是说,每次使用类对象.属性(或者 getattr(类对象,属性值))的调用方式时,都会隐式地调用 getattribute(),它会按照下列顺序查找该属性:
- 验证该属性是否为类实例对象的数据描述符;
- 如果不是,就查看该属性是否能在类实例对象的 dict 中找到;
- 最后,查看该属性是否为类实例对象的非数据描述符。
数据描述符:实现了 setter 和 getter 方法的描述符类被称为数据描述符。
非数据描述符:只实现了 getter 方法,则称为非数据描述符。