python學習之類的裝飾器進階版

裝飾器能夠修飾函數,一樣,也能夠修飾類python

    • 裝飾器閉包

      def deco(func):
          print('======>被修飾的')
      return func架構

    • 裝飾器裝飾函數的方式,語法糖函數

      @deco
      def test():
          print("這是函數")
      接下來運行,不調用:對象

      結果就是:作用域

      ======>被修飾的it

    • 一樣,裝飾器裝飾類的方式for循環

    • @deco
      class Test:
          passclass

      運行獲得test

      ======>被修飾的

    • 發現,修飾函數和修飾類,是同樣的!

    • 由於,對於python而言,一切皆對象,函數是對象,類也是對象!

    • 上述裝飾器均不嚴謹,圖方便寫的,實際寫的時候,仍是須要遵循規則

    • 裝飾器裝飾 類,那麼應該就是爲 類 增長新的功能,至目前,咱們學過的對類進行操做,有對類中屬性進行 增 刪 改 查 的四個功能,那麼,裝飾器應該就是「增長」這一項了。如上,我類中直接pass,如何使用裝飾器給他其中增長屬性?

    • 在類外定義屬性怎麼辦,類名+屬性 = 值,例如:

      class Test:
          pass

      Test.x = 1
      Test.y = 2
      用__dict__查看其下屬性內容
      print(Test.__dict__)

      結果以下:

      {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None, 'x': 1, 'y': 2}

      咱們發現,x=1,y=2 被寫進去了,

    • 接下來,咱們來寫裝飾器,給這個類增長屬性

      def deco(obj):

          obj.x = 1
          obj.y = 2
          obj.z = 3
          return obj

      @deco
      class Test:
          pass

      查看其下屬性

      print(Test.__dict__)

      結果爲:{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None, 'x': 1, 'y': 2, 'z': 3}

      目的很簡單的達成了

    • 問題來了,代碼要開放,若是我還有其餘一百個類須要修改,恰恰每一個類增長的內容還不同,怎麼辦,如今這個裝飾器,是寫死了的,若是讓這段代碼更加靈活?

    • 同時,咱們對比下裝飾器的原則:

      一、不改變被修飾函數的源代碼:√

      二、不改變被修飾函數的調用方法:√

            類的實例化就一種,,,沒什麼改不改的

      也就是說,上面這段裝飾器代碼,是合格的,接下來就是怎麼加工,讓他更加靈活!

    • 換而言之,我傳入其中的x y z 幾個參數,須要由我指定也就是說,要由我來輸入代碼中,但這段代碼的參數,已經有了,是語法糖的規則,類名。

    • 那麼,我學函數裝飾器同樣,在裝飾器內部嵌套一層呢?

      很惋惜,外部做用域,沒法獲取內部做用域的變量值

    • 往左不行,那就往右,我在他外面嵌套一層,把參數傳到他的上一層做用域,他做爲內層來獲取上層總能夠了吧!

    • def ti(**kwargs)由於屬性都是關鍵字參數,這裏直接用kwargs

      爲了運行內部代碼,須要使用閉包外層返回的值應該爲內部函數名deco

      初步代碼架構以下:

      def ti(**kwargs):
          def deco(obj):
              return obj
          return deco

      接下來,咱們須要改寫內部函數,讓內部函數獲取外部函數傳入的關鍵字參數,須要挨個取出來,放進函數中去做爲屬性。

      emmmmmmmmmmmmmmmmmmmmm,挨個取出來,我想到了for循環

      for key,value in kwargs.items()

      用for循環取出其中的key值和value值,接下來,就是把它放進去類裏面做爲屬性了。

    • 增長屬性的方法是什麼來着,設置attr,即setattr

      setattr(obj,key,value)

    • 把上述代碼整合下:

      def ti(**kwargs):
          def deco(obj):
              for key,value in kwargs.items():
                  setattr(obj,key,value)
              return obj
          return deco

      這裏要注意的,ti函數是有傳入值的,這個傳入值,那麼在修飾類的時候,這裏傳入的,就應該是屬性的名和屬性值

      @ti(x= 1)

      class Test:
          pass

    • 咱們再反過來檢查下代碼:

      @是語法糖,自己實際上是個賦值操做,這一步是從右邊往左邊運行,應該是這樣的內容

      Test = ti(x = 1)(Test)

      依次運行上述內容,先來ti(x=1)其返回值是deco,這段代碼其實就是Test = deco(Test),也就是@deco,x = 1 這個參數傳入後,在最外層並無用,而是在內部的時候使用for循環從字典{'x' : 1}中取出來,在經過setattr方法來增長到類當中

    • 須要注意的是,setattr,若是遇到同名屬性,會用傳入的屬性覆蓋原來的屬性。

相關文章
相關標籤/搜索