昨天談完 Decorator 的原理 Closure,今天就正式進入 Decorator。
Decorator
是 Python 的一種語法糖(Syntactic sugar),語法糖指的是,加入這種語法對程式語言的功能沒有影響,但是更方便開發者使用。 decorator
允許開發者在不修改原始 function 的前提下,可以擴展或修改該 function,因此 decorator 本質上就是輸入一個 function,再返回一個擴展或修改的 function 回來。
decorator
本身就是 callable 的 function,在定義 decorator 時,會在這個 function 前加上 @。
簡單例子如下:
def go_pass():
pass
@go_pass
def a():
print(1)
昨天談 Closure 時,我們知道在 Python 中,function 可以被傳遞到其他的 function 中,且 function 的返回值可以是一個 function。
decorator 其實就是利用這個特性,一樣來一個簡單的例子:
def dec(func):
def wrapper():
print("before function")
func()
print("after function")
return wrapper
@dec
def hello():
print("Hello World!")
hello()
# before function
# Hello World!
# after function
這裡 decorator 的用法是先把 hello 丟進 dec function,並返回 wrapper , wrapper會把原來丟進去的 function 前後加上 print("before function")
和 print("after function")
,所以才會看到印出 Hello World!
前後有 before function
和 after function
。
@dec hello()
完全等同於 hello = decorator(hello)
def hello():
print("Hello World!")
hello = dec(hello) # 完全等同於 decorator
hello()
# before function
# Hello World!
# after function
前面有提到我們使用 decorator,input 和 output 都會是 function。
但你說它能不能不返回 function? 可以,只是沒人會這樣用 XD
def plus_one(func):
return 3
@plus_one
def plus_two(x):
return x + 2
num = plus_two
print(num) # output = 3
print 出來 output = 3 ,因為它會等同是 plus_one(plus_two),不管帶什麼都會是 return 3。
因為裝飾器本身是 repeat(Hello)
一樣會把 Hello
丟進去 repeat
,只是再多包一層來接收參數。
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def Hello():
print("Hello World!")
Hello()
# Hello World!
# Hello World!
# Hello World!