[python] wraps 小小的工具,大大的不同。正確顯示函式 name 及 docstring。

  • 10939
  • 0

[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

 

 

 

分享