標籤:name 重要 turn ... return 列印 ref wrap style
考察上一節的 @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_decoratordef 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(): passprint test()
執行結果:
[DEBUG] test()...None
對於這種3層嵌套的decorator定義,你可以先把它拆開:
# 標準decorator:def log_decorator(f): def wrapper(*args, **kw): print ‘[%s] %s()...‘ % (prefix, f.__name__) return f(*args, **kw) return wrapperreturn log_decorator# 返回decorator:def log(prefix): return log_decorator(f)
拆開以後會發現,調用會失敗,因為在3層嵌套的decorator定義中,最內層的wrapper引用了最外層的參數prefix,所以,把一個閉包拆成普通的函數調用會比較困難。不支援閉包的程式設計語言要實現同樣的功能就需要更多的代碼。
python中編寫帶參數decorator