<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      描述符詳解

      初學(xué)py的時候大家都說描述符是高級內(nèi)容難度較大,仔細(xì)擼過文檔之后感覺還好,不過用起來確實不那么直觀。

      按照慣例,先來看一下官文API文檔:

      In general, a descriptor is an object attribute with “binding behavior”, one whose attribute access has been overridden by methods in the descriptor protocol: __get__(), __set__(), and __delete__().
      If any of those methods are defined for an object, it is said to be a descriptor.
      

      總的來說,描述符是一個帶有綁定行為的對象屬性,訪問這個對象屬性的時候會被描述符協(xié)議中的方法覆蓋,可以理解為一種hook機(jī)制。

      The following methods only apply when an instance of the class containing the method (a so-called descriptor class) appears in an owner class.
      the descriptor must be in either the owner’s class dictionary or in the class dictionary for one of its parents.
      

      描述符協(xié)議包括三個魔術(shù)方法:

      • object.get(self, instance, owner):通過owner class或其實例訪問描述符實例時被調(diào)用。
      • object.set(self, instance, value):給owner class的中的描述符實例賦值的時候被調(diào)用。
      • object.delete(self, instance):刪除owner class中的描述符實例的時候被調(diào)用,這個方法很少用。

      一個對象只要實現(xiàn)其中之一就是一個描述符。
      描述符必須在owner class或者其父類的屬性字典中,也就是owner的類屬性,定義成實例屬性無效。

      For instance bindings, the precedence of descriptor invocation depends on the which descriptor methods are defined.
      A descriptor can define any combination of __get__(), __set__() and __delete__().
      If it does not define __get__(), then accessing the attribute will return the descriptor object itself unless there is a value in the object’s instance dictionary.
      If the descriptor defines __set__() and/or __delete__(), it is a data descriptor. 
      if it defines neither, it is a non-data descriptor. 
      
      Normally, data descriptors define both __get__() and __set__(), while non-data descriptors have just the __get__() method.
      Data descriptors with __set__() and __get__() defined always override a redefinition in an instance dictionary.
      In contrast, non-data descriptors can be overridden by instances.
      

      如果描述符class中沒有定義__get__()方法,那么訪問描述符實例僅僅會返回一個描述符class的實例,而不會觸發(fā)調(diào)用。
      如果定義了__set__()和__delete__ ()其中之一就是一個數(shù)據(jù)描述符
      如果都沒有定義,即只定義__get__,那么就是一個非數(shù)據(jù)描述符

      通常,數(shù)據(jù)描述符會同時定義__get__()和__set__(),非數(shù)據(jù)描述符僅定義__get__()。

      其實,基礎(chǔ)概念看到這里就可以了,弄清什么時候觸發(fā)__get__()、什么時候觸發(fā)__set__()即可。
      至于描述符實例啥時候會被覆蓋這一點經(jīng)常會把萌新弄暈,而且這一點屬于面向?qū)ο蠡A(chǔ)知識,跟描述符本身無關(guān)。


      下面舉兩個例子簡單看一下非數(shù)據(jù)描述符和數(shù)據(jù)描述符。

      非數(shù)據(jù)描述符:

      class A:
          def __init__(self):
              self.a = 'a'
              print('A init')
      
          def __get__(self, instance, owner):
              print('A.__get__ {} {} {}'.format(self, instance, owner))
              return self
      
      class B:
          x = A()
          def __init__(self):
              self.b = 'b'  # 這個僅僅是一個實例屬性,與描述符無關(guān)
              # self.x = 'x'   # 由于描述符沒有定義__set__方法,這里不能這樣定義,實例化的時候?qū)嵗龑傩詴采w類屬性,描述符將被覆蓋
              print('B init')
      
      print(B.x)  # 這里會調(diào)用A的__get__方法,返回的是__get__方法的返回值
      # A init
      # A.__get__ <__main__.A object at 0x10302d5c0> None <class '__main__.B'>
      # <__main__.A object at 0x10302d5c0>
      
      b = B()
      print(b.x)  # 這里也會調(diào)用A的__get__方法,不過這里會把b實例傳遞進(jìn)去
      # B init
      # A.__get__ <__main__.A object at 0x10302d5c0> <__main__.B object at 0x10302d748> <class '__main__.B'>
      # <__main__.A object at 0x10302d5c0>
      
      # 為了能夠獲取描述符實例的屬性,可以讓__get__方法返回self
      print(b.x.a)
      # A.__get__ <__main__.A object at 0x10302d5c0> <__main__.B object at 0x10302d748> <class '__main__.B'>
      # a
      
      print(b.b)
      # b
      

      數(shù)據(jù)描述符:

      class A:
          def __init__(self):
              self.a = 'a'
              print('A init')
      
          def __get__(self, instance, owner):
              print('A.__get__ {} {} {}'.format(self, instance, owner))
              return self
      
          def __set__(self, instance, value):
              print('A.__set__ {} {} {}'.format(self, instance, value))
              instance.c = value
      
      class B:
          x = A()
          def __init__(self):
              self.b = 'b'
              self.x = 'c'    # 由于描述符定義了__set__方法,這里對描述符實例的賦值操作會調(diào)用描述符的__set__方法,并沒有覆蓋描述符
              print('B init')
      
      b = B()
      print(b.__dict__)
      # {'b': 'b', 'c': 'c'}
      
      b.x = 100
      print(b.__dict__)
      # {'b': 'b', 'c': 100}
      

      由于涉及兩個類和其實例的交互,闡述起來也不是很容易呢。不過仔細(xì)捋一下,其實并不是很復(fù)雜,有沒有?


      最后,需要提醒一下,staticmethod、classmethod、property三個內(nèi)置裝飾器都是通過描述符實現(xiàn)的。
      其中,staticmethod和classmethod是通過非數(shù)據(jù)描述符實現(xiàn)的,property是通過數(shù)據(jù)描述符實現(xiàn)的。

      Python methods (including staticmethod() and classmethod()) are implemented as non-data descriptors.
      The property() function is implemented as a data descriptor.
      

      通常大家知道怎么用這幾個裝飾器,但往往可能不會細(xì)究是如何實現(xiàn)的,下篇繼續(xù)來說這幾個裝飾器是如何實現(xiàn)的。

      參考:
      https://docs.python.org/3/reference/datamodel.html#implementing-descriptors
      https://docs.python.org/3/reference/datamodel.html#invoking-descriptors

      posted @ 2019-01-05 05:44  KeithTt  閱讀(867)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久国产av影片| 国产免费久久精品44| 精品人妻无码一区二区三区性| 99久久婷婷国产综合精品青草漫画 | 国产91丝袜在线观看| 在线观看亚洲欧美日本| 青草视频在线观看视频| 国产精品aⅴ免费视频| 国产精品一品二区三四区| 精品久久精品午夜精品久久 | 国产真实乱对白精彩久久| 国产午夜福利一区二区三区| 国内精品自线在拍| 免费人成自慰网站| 国产亚洲精品久久久久久无亚洲 | 爽爽精品dvd蜜桃成熟时电影院| 国产色视频一区二区三区| 成年午夜免费韩国做受视频| 日本真人做爰免费的视频| 国产女人看国产在线女人| 成人动漫综合网| 久久国产精品无码网站| 亚洲国产精品男人的天堂| 亚洲春色在线视频| 日韩精品亚洲不卡一区二区| 亚洲国产成人资源在线| 成人精品色一区二区三区| 欧美人与禽2o2o性论交| 四虎国产精品永久入口| 色婷婷狠狠久久综合五月| 亚洲中文字字幕精品乱码| 中文字幕日韩有码第一页| www插插插无码视频网站| 婷婷成人丁香五月综合激情| 最近中文字幕日韩有码| 阳西县| 黑人巨茎大战白人美女| 亚洲天堂av 在线| 艳妇臀荡乳欲伦交换h在线观看 | 久久96热在精品国产高清| 日本熟妇XXXX潮喷视频|