33.描述器(二)
阿新 • • 發佈:2021-06-11
(三十四)描述器二
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 objectat 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__
屬性裡面也沒有找到 --> 就會在類或父類的非資料描述器中進行查詢;