functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
- 此函数的作用是更新包装器函数看起来像被它包装起来的函数。它的可选的元组参数列举了原函数声明的哪些属性可直接与包装器函数的属性相匹配,包装器哪些属性需更新以符合原函数的属性。这些参数的默认值是模块级的常量WRAPPER_ASSIGNMENTS(包装器函数声明的__module__ ,__ name __, __ qualname __, __ annotations __ 和 __ doc __ 文档字符串)和 WRAPPER_UPDATES(更新包装器函数的 __ dict __ ,等实例的字典信息)
- 为了方便获的原函数内部的信息和其它目的,这个函数将自动为包装器函数添加一个 __ wrapped __ 属性,以此为关联被包装的函数。
- 这个函数的主要目的是用在装饰器函数里,装饰器函数装饰一个函数,并且返回的包装函数。如果这个包装函数没有更新,返回的函数的元数据将使用包装函数的定义,而不是原函数的定义,因为那些通常是没有多大用处的。
- update_wrapper()可以与其它可调用函数一起使用,任可在assigned o或updated中声明的属性,如果在被包装的函数找不到,那么就会被忽略(也就是说这个函数不会把这些性属赋予包装器涵数)。如果包装器函数本身不含所有在updated中命名的属性,那么将报属性错误 AttributeError
@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
- 当我们定义一个包装器函数时,可以用这个便捷函数调用update_wrapper() 函数作为函数的装饰器。
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')
如上所述,@wraps(f)将调用update_wrapper() 函数作为wrapper函数的装饰器,使闭包更新并保留原函数的属性。
>>> example()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'
感悟:原函数被装饰后,调用原函数其实调用的是一个闭包,也就是装饰器返回的包装器函数return wrapper。可以说原函数经过装饰后变成了一个新的函数,只是函数名相同的函数而已。
官网链接:https://docs.python.org/3/library/functools.html?highlight=functools wraps#functools.update_wrapper