[python] wraps 小小的工具,大大的不同。正確顯示函式 name 及 docstring。
今天在學習 mosql [1] 的時候,發現裡面的 decorator 裡面,都再包了一個 wraps(f) 的 decorator。為什麼?查詢了一下官方文件 functools [2],它提到:
This is a convenience function for invoking partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) as a function decorator when defining a wrapper function.
我看著它的範例發呆,好像加不加 wraps,沒什麼差別呢。立即用程式試一下:
def my_decorator(f):
def wrapper(*args, **kwds):
print 'Calling decorated function'
return f(*args, **kwds)
return wrapper@my_decorator
def example():
"""Docstring"""
print 'Called example function'example()
>>> ================================ RESTART ================================
>>>
Calling decorated function
Called example function
>>>
不過,在最底下一句說,如果不使用 wraps 的話,function 的 name 及 docstring 會不如預期。例如,我們預期以下的樣子:
print example.__name__ # it should be "example"
print example.__doc__ # is should be "Docstring"
但實際上卻是:
print example.__name__
print example.__doc__
>>> ================================ RESTART ================================
>>>
wrapper
None
>>>
所以,wraps 的用途就在於讓使用 decorator 的函式,能夠正確將 name 及 docstring 顯示出來。
from functools import wraps
def my_decorator(f):
@wraps(f)
def wrapper(*args, **kwds):
print 'Calling decorated function'
return f(*args, **kwds)
return wrapper@my_decorator
def example():
"""Docstring"""
print 'Called example function'example()
print example.__name__
print example.__doc__
>>> ================================ RESTART ================================
>>>
Calling decorated function
Called example function
example
Docstring
>>>
不過,大家不覺得很可愛嗎?解決 decorator 的問題,又再用一次 decorator。
延伸:在範例中,@wraps(f) 後面有帶括號及參數,這個部份值得再研究下去。
參考:
[1] https://github.com/moskytw/mosql
[2] http://docs.python.org/2/library/functools.html