33.描述器(二)
(三十四)描述器二
4:数据描述器
# 示例1: class XKD1: def __init__(self): self.course = 'Python' print('XKD1.__init__') def __get__(self, instance, owner): # 这里的self为XKD1的实例. instance为实例, 如果是类访问,那么instance为None. owner是调用者的类 print('self={} instance={} owner={}'.format(self, instance, owner)) # todo: 返回XKD1的实例self return self class XKD2: x = XKD1() def __init__(self): print('XKD2.__init__') self.y = XKD1() # 没有调用__get__方法 print('*'*100) print(XKD2.x.course) # self=<__main__.XKD1 object at 0x108c39b38> instance=None owner=<class '__main__.XKD2'> print('*'*100) obj = XKD2() print('*'*100) print(obj.y) # 返回 <__main__.XKD1 object at 0x103b56cf8> 小结: 当非数据描述器是实例的变量时,实例访问非数据描述器不会调用__get__方法,只是访问了描述器类的实例 # 示例2:数据描述器 class XKD1: def __init__(self): self.course = 'Python' print('XKD1.__init__') def __get__(self, instance, owner): print('self={} instance={} owner={}'.format(self, instance, owner)) return self def __set__(self, instance, value): print('self={} instance={} value={}'.format(self, instance, value)) self.course = value class XKD2: x = XKD1() def __init__(self): print('XKD2.__init__') self.y = XKD1() # 调用了__get__方法 print('*'*100) print(XKD2.x.course) print('*'*100) obj = XKD2() print('*'*100) print(obj.x) 小结: 当数据描述器是实例的变量时,实例访问数据描述器会调用描述器的__get__方法
5:非数据描述器和数据描述器的访问顺序
# 示例1:非数据描述器 class XKD1: def __init__(self): self.course = 'Python' print('XKD1.__init__') def __get__(self, instance, owner): print('self={} instance={} owner={}'.format(self, instance, owner)) return self class XKD2: x = XKD1() def __init__(self): print('XKD2.__init__') self.x = 'XKD1' # 实例访问的是自己的__dict__中的x属性 print('*'*100) print(XKD2.x.course) print('*'*100) obj = XKD2() print('*'*100) print(obj.x) # 返回 'XKD1' # 示例2:数据描述器 class XKD1: def __init__(self): self.course = 'Python' print('XKD1.__init__') def __get__(self, instance, owner): print('self={} instance={} owner={}'.format(self, instance, owner)) return self def __set__(self, instance, value): print('self={} instance={} value={}'.format(self, instance, value)) self.course = value class XKD2: x = XKD1() def __init__(self): print('XKD2.__init__') self.x = 'XKD1' # 实例这里访问的是类属性x,也就是数据描述器,会调用数据描述器的__get__方法 print('*'*100) print(XKD2.x.course) print('*'*100) obj = XKD2() print('*'*100) print(obj.x) # 调用__get__方法,返回 XKD1实例 小结: 一个类实例的查找属性顺序为:先查找类或父类中的数据描述器属性, 在查找自己__dict__中的属性,再查找类或父类的非数据描述器, 数据描述器优先于实例的__dict__, 实例的__dict__属性优先于非数据描述器, 当存在描述器的时候,属性的查找顺序为:类或父类的数据描述器属性 --> 实例的__dict__属性 --> 类或父类的非数据描述器属性
4.数据描述器
-
当非数据描述器是实例的变量时,实例访问非数据描述器不会调用
__get__
方法,只是访问了描述器类的实例; -
当数据描述器是实例的变量时,实例访问数据描述器会调用描述器的
__get__
方法;
5.非数据描述器和数据描述器的访问顺序
当存在描述器的时候,一个类实例的查找属性顺序为:先查找类或父类中是否有数据描述器属性,如果有那么,先访问数据描述器,如果没有数据描述器 --> 那么就会查找自己实例的__dict__
属性,如果__dict__
属性里面也没有找到 --> 就会在类或父类的非数据描述器中进行查找;