Pthon魔术方法(Magic Methods)-描述器
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.描述器概述
1>.描述器定义
Python中,一个类实现了"__get__","__set__","__delete__"三个方法中的任何一个方法,就是描述器。 实现着三个中的某些方法,就支持了描述器协议:
仅实现了"__get__",就是非数据描述器,即non-data descriptor
实现了"__get__","__set__"就是数据描述器,即data descriptor
"__delete__"方法有同样的效果,有了这个方法,也是数据描述器。
如果一个类属性设置为描述器实例,那么它被称为owner属主。
当该类的该类属性被查找,设置,删除时,就会调用描述器相应的方法。
2>.非数据描述器案例
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 class A: 7 def __init__(self): 8 self.a1 = "a1" 9 print("A.init") 10 11 def __get__(self, instance, owner): 12 """ 13 因为定义了"__get__"方法,类A就是一个描述器,使用类B或者类B的实例来对x属性读取,就是对类A的实例的访问,就会调用"__get__"方法 14 参数说明如下: 15 self指代当前实例对象,即调用者,在本例中它对应的是A的实例 16 instance是owner的实例,在本例中它的值可能有两种: 17 None表示不是B类的实例,对应调用B.x 18 <__main__.B object at 0x00000284CBF675C8>表示是B的实例,对应调用B().x 19 owner是属性的所属的类 20 """ 21 print("A.__get__ {} {} {}".format(self,instance,owner)) 22 return self 23 24 class B: 25 x = A() #此时我们可以说x是非数据描述器,因为A()类中仅实现了"__get__"方法 26 def __init__(self): 27 print("B.init") 28 self.x = "b.x" #增加实例属性"x",由于这里的实例属性名称和上面的非数据描述器名称一致,此时赋值即定义,实例x变量会将类中的描述器标识符覆盖(因为A类中没有"__set__"方法可调用)。 29 30 31 32 print("-" * 20) 33 print(B.x) 34 print(B.x.a1) 35 36 print("=" * 20) 37 b = B() 38 print(b.x) 39 # print(b.x.a1) #由于此时"b.x"访问到的是实例的属性,而不是非数据描述器,因此报错"AttributeError: 'str' object has no attribute 'a1'"
A.init -------------------- A.__get__ <__main__.A object at 0x000001536AD65588> None <class '__main__.B'> <__main__.A object at 0x000001536AD65588> A.__get__ <__main__.A object at 0x000001536AD65588> None <class '__main__.B'> a1 ==================== B.init b.x