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
以上代码执行结果戳这里

相关文章: