45. 爲被裝飾函數保存元數據

在函數對象中保存着一些函數的元數據,例如:

__name__        函數的名字
__doc__         函數文檔字符串
__module__      函數所屬模塊名
__dict__        屬性字典
__default__     默認參數元組
...

在使用裝飾器後,再訪問上面這些屬性時,看到的是內部包裹函數的元數據,原來函數的元數據便丟失了。

要求:爲被裝飾函數保存元數據。

解決方案:

  1. 使用標準庫functools中的update_wrapper()函數更新內部包裹函數的屬性爲被包裹函數的屬性。

  2. 使用標準庫functools中的wraps裝飾內部包裹函數,可以指定將原函數的某些屬性,更新到包裹函數。


  • 對於functools.update_wrapper()函數:
functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

此函數的主要用途是包裝修飾函數並返回wrapper函數。wrapper函數是包裹函數,wrapped函數就是被包裹函數。

更新wrapper函數,使其看起來像wrapped函數。可選參數assigned是元組,用於指定將原始函數的哪些屬性直接分配給wrapper函數上匹配的屬性,以及使用原始函數的相應屬性更新wrapper函數的哪些屬性(比如__dict__屬性字典)。

>>> from functools import WRAPPER_ASSIGNMENTS

>>> WRAPPER_ASSIGNMENTS
('__module__', '__name__', '__qualname__', '__doc__', '__annotations__')

>>> from functools import WRAPPER_UPDATES

>>> WRAPPER_UPDATES
('__dict__',)

一般來說,使用默認參數即可,即functools.update_wrapper(wrapper, wrapped)

  • 對於functools.wraps()函數:
functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

用於在定義wrapper函數(包裹函數)時調用update_wrapper()作爲函數裝飾器。它等價於partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)。作爲wrapper函數的裝飾器時參數是wrapped函數名(被包裹函數名)。


  • 方案1示例:
from functools import update_wrapper

def my_decorator(func):
    def wrap(*args ,**kwargs):
        '''某功能包裹函數'''
        #此處實現某種功能
        return func(*args ,**kwargs)
    update_wrapper(wrap, func)              #保留被裝飾函數元數據
    return wrap

@my_decorator
def xxx_func(a, b):
    '''xxx_func函數文檔:...'''
    pass

print(xxx_func.__name__)
print(xxx_func.__doc__)

xxx_func                #結果
xxx_func函數文檔:...

  • 方案2示例:
from functools import wraps

def my_decorator(func):
    @wraps(func)                #保留被裝飾函數元數據
    def wrap(*args ,**kwargs):
        '''某功能包裹函數'''
        #此處實現某種功能
        return func(*args ,**kwargs)
    return wrap

@my_decorator
def xxx_func(a, b):
    '''xxx_func函數文檔:...'''
    pass

print(xxx_func.__name__)
print(xxx_func.__doc__)

xxx_func                #結果
xxx_func函數文檔:..

上面兩種方案都可以爲被裝飾函數保存元數據,方案2更爲簡便。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章