如今,咱們已經明白了裝飾器的原理。接下來,咱們還有不少事情須要搞清楚。好比:裝飾帶參數的函數、多個裝飾器同時裝飾一個函數、帶參數的裝飾器和類裝飾器。python
def foo(func): # 接收的參數是一個函數名 def bar(x, y): # 這裏須要定義和被裝飾函數相同的參數 print("這裏是新功能...") # 新功能 func(x, y) # 被裝飾函數名和參數都有了,就能執行被裝飾函數了 return bar # 定義一個須要兩個參數的函數 @foo def f1(x, y): print("{}+{}={}".format(x, y, x+y)) # 調用被裝飾函數 f1(100, 200)
輸出:閉包
這裏是新功能...
100+200=300
def foo1(func): print("d1") def inner1(): print("inner1") return "<i>{}</i>".format(func()) return inner1 def foo2(func): print("d2") def inner2(): print("inner2") return "<b>{}</b>".format(func()) return inner2 @foo1 @foo2 def f1(): return "Hello Andy" # f1 = foo2(f1) ==> print("d2") ==> f1 = inner2 # f1 = foo1(f1) ==> print("d1") ==> f1 = foo1(inner2) ==> inner1 ret = f1() # 調用f1() ==> inner1() ==> <i>inner2()</i> ==> <i><b>inner1()</b></i> ==> <i><b>Hello Andy</b></i> print(ret)
被裝飾的函數能夠帶參數,裝飾器一樣也能夠帶參數。函數
回頭看咱們上面寫得那些裝飾器,它們默認把被裝飾的函數當成惟一的參數。可是呢,有時候咱們須要爲咱們的裝飾器傳遞參數,這種狀況下應該怎麼辦呢?spa
接下來,咱們就一步步實現帶參數的裝飾器:code
首先咱們來回顧下上面的代碼:orm
def f1(func): # f1是咱們定義的裝飾器函數,func是被裝飾的函數 def f2(*arg, **kwargs): # *args和**kwargs是被裝飾函數的參數 func(*arg, **kwargs) return f2
從上面的代碼,咱們發現了什麼?string
個人裝飾器若是有參數的話,沒地方寫了…怎麼辦呢?it
仍是要使用閉包函數!io
咱們須要知道,函數除了能夠嵌套兩層,還能嵌套更多層:function
# 三層嵌套的函數1 def f1(): def f2(): name = "Andy" def f3(): print(name) return f3 return f2
嵌套三層以後的函數調用:
f = f1() # f --> f2 ff = f() # ff --> f3 ff() # ff() --> f3() --> print(name) --> Andy
注意:在內部函數f3
中可以訪問到它外層函數f2
中定義的變量,固然也能夠訪問到它最外層函數f1
中定義的變量。
# 三層嵌套的函數2 def f1(): name = "Andy" def f2(): def f3(): print(name) return f3 return f2
調用:
f = f1() # f --> f2 ff = f() # ff --> f3 ff() # ff() --> f3() --> print(name) --> Andy
好了,如今咱們就能夠實現咱們的帶參數的裝飾器函數了:
# 帶參數的裝飾器須要定義一個三層的嵌套函數 def d(name): # d是新添加的最外層函數,爲咱們原來的裝飾器傳遞參數,name就是咱們要傳遞的函數 def f1(func): # f1是咱們原來的裝飾器函數,func是被裝飾的函數 def f2(*arg, **kwargs): # f2是內部函數,*args和**kwargs是被裝飾函數的參數 print(name) # 使用裝飾器函數的參數 func(*arg, **kwargs) # 調用被裝飾的函數 return f2 return f1
上面就是一個帶參裝飾器的代碼示例,如今咱們來寫一個完整的應用:
def d(a=None): # 定義一個外層函數,給裝飾器傳參數--role def foo(func): # foo是咱們原來的裝飾器函數,func是被裝飾的函數 def bar(*args, **kwargs): # args和kwargs是被裝飾器函數的參數 # 根據裝飾器的參數作一些邏輯判斷 if a: print("歡迎來到{}頁面。".format(a)) else: print("歡迎來到首頁。") # 調用被裝飾的函數,接收參數args和kwargs func(*args, **kwargs) return bar return foo @d() # 不給裝飾器傳參數,使用默認的'None'參數 def index(name): print("Hello {}.".format(name)) @d("電影") # 給裝飾器傳一個'電影'參數 def movie(name): print("Hello {}.".format(name)) if __name__ == '__main__': index("Andy") movie("Andy")
輸出:
歡迎來到首頁。 Hello Andy. 歡迎來到電影頁面。 Hello Andy.
除了用函數去裝飾函數外,咱們還可使用類去裝飾函數。
class D(object): def __init__(self, a=None): self.a = a self.mode = "裝飾" def __call__(self, *args, **kwargs): if self.mode == "裝飾": self.func = args[0] # 默認第一個參數是被裝飾的函數 self.mode = "調用" return self # 當self.mode == "調用"時,執行下面的代碼(也就是調用使用類裝飾的函數時執行) if self.a: print("歡迎來到{}頁面。".format(self.a)) else: print("歡迎來到首頁。") self.func(*args, **kwargs) @D() def index(name): print("Hello {}.".format(name)) @D("電影") def movie(name): print("Hello {}.".format(name)) if __name__ == '__main__': index("Andy") movie("Andy")
咱們上面全部的例子都是裝飾一個函數,返回一個可執行函數。Python中的裝飾器除了能裝飾函數外,還能裝飾類。
可使用裝飾器,來批量修改被裝飾類的某些方法:
# 定義一個類裝飾器 class D(object): def __call__(self, cls): class Inner(cls): # 重寫被裝飾類的f方法 def f(self): print("Hello Andy.") return Inner @D() class C(object): # 被裝飾的類 # 有一個實例方法 def f(self): print("Hello world.") if __name__ == '__main__': c = C() c.f()