描述符通过描述符协议实现,任何实现或部分实现以下方法的类,都可以作为描述符使用。
def __get__(self, instance, owner): ... def __set__(self, instance, value): ... def __delete__(self, instance): ....
__get__ 方法接收三个参数:self为描述符实例自身; instance指访问属性所属的实例;owner指描述符实例附加到的类。
__set__方法的前两个参数于__get__方法相同,第三个参数value为需要赋值的属性。
__delete__方法的两个参数与__get__方法的前两个参数相同。
定义一个简单的描述符,和描述符的托管类,进行测试
class Descriptor: def __init__(self): pass def __get__(self, instance, owner): return self, instance, owner def __set__(self, instance, value): print(self, instance, value) def __delete__(self, instance): print(self, instance) class ClassA(object): descriptor = Descriptor()
将ClassA实例化为对象a,并分别从实例、类层面读取描述符。
观察执行结果:当通过实例访问时,instance为当前描述符托管的实例,而通过类访问时,instance为None。但是无论通过实例或类访问,owner都为描述符所属的类。
# 实例化为对象a a = ClassA() # 从实例取值 print(a.descriptor) # (<__main__.Descriptor object at 0x10c157438>, <__main__.ClassA object at 0x10c1574a8>, <class '__main__.ClassA'>) # 从类取值 print(ClassA.descriptor) # (<__main__.Descriptor object at 0x10c157438>, None, <class '__main__.ClassA'>)
对描述符的进行赋值,观察执行结果:可以发现第一个参数是描述符自身,第二个参数是描述符托管的实例,第三个参数是赋值给描述符的值
# 对描述符进行赋值 a.descriptor = 2 # <__main__.Descriptor object at 0x10f0b1518><__main__.ClassA object at 0x10f0b1588> 2
上面就是基本的描述符协议实现。