考察上一節的 @log 裝飾器:
def log(f):
def fn(x):
print('call ' + f.__name__ + '()...')
return f(x)
return fn
發現對于被裝飾的函數,log打印的語句是不能變的(除了函數名)。
如果有的函數非常重要,希望打印出'[INFO] call xxx()...'。
有的函數不太重要,希望打印出'[DEBUG] call xxx()...'。
這時,log函數本身就需要傳入'INFO'或'DEBUG'這樣的參數,類似這樣:
@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('[{}] {}()...'.format(prefix, f.__name__))
return f(*args, **kw)
return wrapper
return log_decorator
@log('DEBUG')
def test():
pass
test()
執行結果:
[DEBUG] test()...
對于這種三層嵌套的decorator定義,你可以先把它拆開:
# 標準decorator:
def log_decorator(f):
def wrapper(*args, **kw):
print('[{}] {}()...'.format(prefix, f.__name__))
return f(*args, **kw)
return wrapper
return log_decorator
# 返回decorator:
def log(prefix):
return log_decorator(f)
上一節的@performance只能打印秒,請給 @performace 增加一個參數,允許傳入's'或'ms':
@performance('ms')
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
要實現帶參數的@performance,就需要實現:
?my_func = performance('ms')(my_func)
需要三層嵌套的decorator來實現。
參考答案:
import time
def performance(unit):
def perf_decorator(f):
def wrapper(*args, **kwargs):
t1 = time.time()
r = f(*args, **kwargs)
t2 = time.time()
t = (t2 - t1) * 1000 if unit == 'ms' else (t2 - t1)
print('call {}() in {} {}'.format(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(10)
請驗證,完成請求
由于請求次數過多,請先驗證,完成再次請求
打開微信掃碼自動綁定
綁定后可得到
使用 Ctrl+D 可將課程添加到書簽
舉報