1. 程式人生 > 其它 >33.描述器(二)

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__屬性裡面也沒有找到 --> 就會在類或父類的非資料描述器中進行查詢;