裝飾器能夠修飾函數,一樣,也能夠修飾類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,若是遇到同名屬性,會用傳入的屬性覆蓋原來的屬性。