摘錄整理于imooc
1. 一個帶參數的decorator
例子
例子是根據 @performance('time_type')
攜帶的時間類型來輸出所裝飾的函數factorial
的執行時間。
import time
import functools
from past.builtins.noniterators import reduce
def performance(unit):
def perf_decorator(f):
# @functools.wraps應該作用在返回的新函數上。
@functools.wraps(f)
def wrapper(*args, **kw):
t1 = time.time()
r = f(*args, **kw)
t2 = time.time()
t = (t2 - t1) * 1000 if unit == 'ms' else (t2 - t1)
print('call %s() in %f %s' % (f.__name__, t, unit))
return r
return wrapper
return perf_decorator
@performance('ms')
def factorial(n):
return reduce(lambda x, y: x * y, range(1, n + 1))
factorial(10000)
print(factorial.__name__)
2.代參數的decorator
為什么要包三層(三階)?
# 為什么包三層(三階)
@log('DEBUG')
def my_func():
pass
# 把上面的定義翻譯成高階函數的調用,就是:
my_func = log('DEBUG')(my_func)
# 上面的語句看上去還是比較繞,再展開一下:
log_decorator = log('DEBUG')
my_func = log_decorator(my_func)
# 上面的語句又相當于:
log_decorator = log('DEBUG')
@log_decorator
def my_func():
pass
# 所以,帶參數的log函數首先返回一個decorator函數,再讓這個decorator函數接收my_func并返回新函數:
def log(prefix):
def log_decorator(f):
def wrapper(*args, **kw):
print('[%s] %s()...' % (prefix, f.__name__))
return f(*args, **kw)
return wrapper
return log_decorator
@log('DEBUG')
def test():
pass
print(test())
簡而言之,最外層負責把decorator
的參數DEBUG
傳進來,既然decorator
攜帶的參數已經傳進來,那么剩下的中間層和里層就是一個不帶參的decorator
的語法糖。反之而推,要多攜帶參數,肯定是需要多加一階。