裝飾器能做什麼
相信很多讀者都聽過AOP,所以筆者在此就不加贅述了,而裝飾器就是實現AOP的一種編寫程序。簡單解釋裝飾器的功用就是,再不更改程序的狀況下能夠附加功能。在介紹如何實作裝飾器前,先告訴大家如何使用。
使用裝飾器
大家先看一下下列例子:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
相信各位讀者對於這例子應該不陌生,沒錯這就是第一天介紹給大家的例子,而裝飾器在哪呢,
這就是裝飾器,因為有它Python可以寫的更簡潔。@app.route("/")
實作一個裝飾器
在認識如何使用裝飾器後要介紹大家如何自訂一個裝飾器,請各位讀者看看以下例子:
def printHello(func):
def wrapper():
print('Hello')
return func()
return wrapper
@printHello
def printWorld():
print('World')
printWorld()
如此第一個裝飾器完成了,相信大家應該知道執行後會顯示以下內容:
Hello
World
就這樣我們建立了一個會印出Hello的裝飾器,所以當我們需要一個印出Hello Kitty的函式該如何寫呢?相信許多讀者已經有答案了,如果還沒有想法請看以下例子:
@printHello
def printKitty():
print('Kitty')
printKitty()
裝飾器的原理
裝飾器是怎樣一個語法,為什麼他能夠這樣寫,再來就是他這樣寫是代表甚麼呢?眼尖的讀者可以看到一個特別的符號
是代表甚麼呢?請見以下例子:@
`這就是人稱Python
`@
`[語法糖](https://zh.wikipedia.org/wiki/%E8%AF%AD%E6%B3%95%E7%B3%96)的東西,它可以讓你的程序變得簡潔,而
`@
printWorld = printHello(printWorld)
上述可以說明
。相信這樣的解釋可以讓大家對於裝飾器有更進一步的了解。@
`的功用就是將
`printWorld
`丟到
`printHello
`函式中,而我們之前定義
`printHello
`函式就是將丟進來的參數
`printWorld
`包裝後傳出去。所以這邊最外面的
`printWorld
`所接收到的東西就是包裝後的
`wrapper()
`,所以呼叫
`printWorld
`時其實是呼叫
`wrapper()
`所以會先印出
`Hello
`在執行方法
`printWorld
函式的參數怎麼辦
如果說裝飾器所裝的函式需要輸入參數該如何處理呢,換句話說想要整合printKitty跟printWorld該如何處理呢?相信經過上述的介紹後應該不難處理,不過如果讀者們不知道如何處理請看下列例子吧:
def printHello(func):
def wrapper(arg):
print('Hello')
return func(arg)
return wrapper
@printHello
def printArg(arg):
print(arg)
printArg('World')
printArg('Kitty')
就這樣更進一步的裝飾器完成了,如此裝飾器可以把參數傳達給所定義的函式。
函式的參數很複雜怎麼辦
如果裝飾器所掛載的函式參數很複雜時該如何處置呢,總不能定了一堆類似的裝飾器吧。所以這裡介紹一個通吃的參數輸入定義方式,請見以下例子:
def printHello(func):
def wrapper(*args, **kwargs):
print('Hello')
return func(*args, **kwargs)
return wrapper
@printHello
def printSingle(arg):
print(arg)
@printHello
def printDouble(arg1, arg2):
print(arg1)
print(arg2)
printSingle('World')
printDouble('Kitty', 'Danny')
其中*args, **kwargs是甚麼東西啊?請看下列說明。
*args與**kwargs
其中
指的是任何名子的參數,更進一步請看下列說明:*args
`是一個
`list
`指的是不論個數的輸入參數,
`**kwargs
`是一個
`dict
def func(*args, **kwargs):
for item in args:
print("I'm args and value is {0}".format(item))
for key, value in kwargs.items():
print("I'm kwargs and key and value is {0}={1}".format(key, value))
func([{
'name': 10,
'value': 20
}, 1, 2, 3], 12364)
func(name=1023)
結果顯示如下
"I'm args and value is [{'name': 10, 'value': 20}, 1, 2, 3]"
"I'm args and value is 12364"
"I'm kwargs and key and value is name=1023"
透過這兩個參數可以指定所有的輸入參數,如此裝飾器的功能更強大了,能夠用在更多地方了。
裝飾器也能加參數
處理完掛載的裝飾器之後,如果想要在裝飾器上輸入參數該怎麼辦呢,就看看下列例子吧:
def printArg(arg):
def decorator(func):
def wrapper(*args, **kwargs):
print(arg)
return func(*args, **kwargs)
return wrapper
return decorator
@printArg('Hi')
def sayHiAndPrintArg(arg):
print(arg)
sayHiAndPrintArg('World')
小結
沒想到光一個裝飾器一天還不夠講,明天接續講裝飾器進階的用法,敬請期待。
很棒,感谢分享!