Python 描述器 Descriptors 详解
1、概念介绍
-
描述器 是两个类之间的事
-
描述器一般会用到4个魔术方法,如下:
class A: def __get__(self, instance, owner): pass # self 指代当前实例,调用者 # instance 是owner的实例 # owner 是属性的所属的类 def __set__(self, instance, value): pass def __delete__(self, instance): pass # 3.6以后,新增一个魔术方法 def __set_name__(self, owner, name): pass
-
Python
中,一个类实现了__get__ 、 __set__ 、 __delete__
三个方法中的任何一个方法,就是描述器。实现这三个中的某些方法,就支持了描述器协议 -
仅实现了
__get__
,就是 非数据描述器non-data descriptor
-
实现了
__get__
和__set__
,就是 数据描述器data descriptor
-
如果一个类的类属性设置为描述器实例,那么它就称为
owner
属主 -
当该类的类属性被查找、设置和删除时,就会调用描述器相应的方法
-
属性查找顺序:
数据描述器 优先于 实例的__dict__ 优先于 非数据描述器
-
__delete__
方法有同样的效果,有了这个方法,也是数据描述器 -
数据描述器可以阻止实例对属性的修改
2、通过示例验证
2.1 正常的类属性访问
class A:
def __init__(self):
print('A init')
self.a = 'AAA'
class B:
x = A()
def __init__(self):
print('B init')
self.a = 'BBB'
print(1, B.x)
print(2, B().x)
print(3, B.x.a)
print(4, B().x.a)
b1 = B()
print(5, b1.x)
print(6, b1.x.a)
print(7, b1.a)
print(8, b1.__dict__)
A init
1 <__main__.A object at 0x000001A4A049C580>
B init
2 <__main__.A object at 0x000001A4A049C580>
3 AAA
B init
4 AAA
B init
5 <__main__.A object at 0x000001A4A049C580>
6 AAA
7 BBB
8 {
'a': 'BBB'}
2.2 非数据描述器且实例没有同名属性
# 非数据描述器
# self在哪个类中,就是哪个类的实例
# class B实例没有同名类属性
class A:
def __init__(self):
print('A init')
self.a = 'AAA'
def __get__(self, instance, owner): # 类A 是非数据描述器
print("[=> A.__get__.\nself is {}.\ninstance is {}.\nowner is {}.<=]".format(self, instance, owner))
return self
class B:
x = A() # 对类B或者类B的实例的属性读取,称为对类A的实例访问,就会调用__get__方法
def __init__(self):
print('B init')
self.a = 'BBB'
self.b = A()
print('+' * 55)
print(1, B.x) # 调用__get__方法
print(2, B.x.a) # 调用__get__方法
print('*' * 55)
print(3, B().x) # 调用__get__方法
print(4, B().x.a) # 调用__get__方法
print('=' * 55)
b1 = B()
print(5, b1.x) # 调用__get__方法
print(6, b1.x.a) # 调用__get__方法
print('+' * 55)
print(7, b1.b) # 实例属性是类属性时,并不会调用 非数据描述器 的__get__方法
print(8, b1.__dict__)
A init
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
[=> A.__get__.
self is <__main__.A object at 0x000001A4A23F1550>.
instance is None.
owner is <class '__main__.B'>.<=]
1 <__main__.A object at 0x000001A4A23F1550>
[=> A.__get__.
self is <__main__.A object at 0x000001A4A23F1550>.
instance is None.
owner is <class '__main__.B'>.<=]
2 AAA
*******************************************************
B init
A init
[=> A.__get__.
self is <__main__.A object at 0x000001A4A23F1550>.
instance is <__main__.B object at 0x000001A4A202EFA0>.
owner is <class '__main__.B'>.<=]
3 <__main__.A object at 0x000001A4A23F1550>
B init
A init
[=> A.__get__.
self is <__main__.A object at 0x000001A4A23F1550>.
instance is <__main__.B object at 0x000001A4A202E070