第一次見到functools.wraps是在 Flask Web開發 中,一直不明白怎么回事。
裝飾器(decorator)是干嘛的?對於受到封裝的原函數來說,裝飾器能夠在那個函數執行前或者執行后分別運行一些代碼,使得可以再裝飾器里面訪問並修改原函數的參數以及返回值,以實現約束定義、調試程序、注冊函數等目標。裝飾器一般返回一個包裝器(wrapper),而functools.wraps就是裝飾包裝器的裝飾器。
先來看一個不使用functools.wraps的裝飾器例子。
1 def tracer(func): 2 def wrapper(*args, **kwargs): 3 result = func(*args, **kwargs) 4 print('%s(%r,%r)->%r'%(func.__name__,args,kwargs,result)) 5 return result 6 return wrapper 7 8 @tracer 9 def fibonacci(n): 10 if n in (0,1): 11 return n 12 return (fibonacci(n-1)+fibonacci(n-2)) 13 14 15 fibonacci(3) 16 print(fibonacci) 17 print('help:') 18 help(fibonacci)
輸出結果:
可以看到,裝飾器完全可以正常工作。。。
但是,函數的名字變成裝飾器中的包裝器了!!!help內置函數也失效了
也就是說,原函數的屬性失效了
如果想要保留原函數的屬性,就可以用到functools.wraps了
1 from functools import wraps 2 def tracer(func): 3 @wraps(func) 4 def wrapper(*args, **kwargs): 5 result = func(*args, **kwargs) 6 print('%s(%r,%r)->%r'%(func.__name__,args,kwargs,result)) 7 return result 8 return wrapper 9 10 @tracer 11 def fibonacci(n): 12 if n in (0,1): 13 return n 14 return (fibonacci(n-1)+fibonacci(n-2)) 15 16 17 fibonacci(3) 18 print(fibonacci) 19 print('help:') 20 help(fibonacci)
輸出結果:
參考資料:Effective Python,第6章 內置模塊