最近發現自己在 Python上的技巧需要提升,雖然以前就知道 Decorator的概念,但我在
實際應用上很少使用,趁此機會來重新理解下。
Decorator簡單來說,是一種 function,並以另一個 function作為輸入,用來擴充輸入
function的功能。
以下面程式碼為例:
def hello_alice(hello_func):
hello_func("Alice")
def say_hello(name):
print (f"Hello {name}")
if __name__ == '__main__':
hello_alice(say_hello)
hello_func("Alice")
def say_hello(name):
print (f"Hello {name}")
if __name__ == '__main__':
hello_alice(say_hello)
Output:
Hello Alice
這裡 hello_alice使用 say_hello當作參數傳入,
hello_alice就是作為 say_hello的
decorator。
Syntactic Sugar
通常 decorator會使用更簡潔的語法糖 "@"包裝,使用上面的範例修改:
def hello_alice(hello_func):
hello_func("Alice")
@hello_alice
def say_hello(name):
print (f"Hello {name}")
if __name__ == '__main__':
say_hello
hello_func("Alice")
@hello_alice
def say_hello(name):
print (f"Hello {name}")
if __name__ == '__main__':
say_hello
Output:
Hello Alice
@hello_alice代表將 say_hello當作參數傳入 hello_alice function。
Inner Functions
Python的 function也能夠在另一個 function中被定義,稱為 inner function。inner function可以
讓 decorator的使用更加靈活:
def greet(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result
return wrapper
@greet
def say_hello(name):
print(f"Hello {name}")
if __name__ == '__main__':
say_hello("Alice")
say_hello("Bob")
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result
return wrapper
@greet
def say_hello(name):
print(f"Hello {name}")
if __name__ == '__main__':
say_hello("Alice")
say_hello("Bob")
Output:
Hello Alice
Hello Bob
Hello Bob
其中 wrapper就是作為 decorator @greet的 inner function。 並且會使用 *args與 **kwargs來接收參數。
Example - Measure Time
一個 decorator經典的範例是用於測量 function執行所花的時間:
import time
def measuretime(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print (func.__name__, end - start)
return result
return wrapper
@measuretime
def count_down(n):
while n > 0:
n -= 1
if __name__ == '__main__':
count_down(500000)
def measuretime(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print (func.__name__, end - start)
return result
return wrapper
@measuretime
def count_down(n):
while n > 0:
n -= 1
if __name__ == '__main__':
count_down(500000)
count_down 0.018976449966430664
使用 decorator @measure的來測量 count_down function所花費的時間。
沒有留言:
張貼留言