为什么我们使用`wraps`而不是`update_wrapper`作为装饰器?

时间:2017-09-27 15:34:58

标签: python python-3.x

装饰者functools.wraps调用方法functools.update_wrapper

我想了解使用wrap代替update_wrapper的必要性。 为什么我们不能使用update_wrapper作为装饰器而不是使用wraps

例如:

from functools import update_wrapper
def wrap1(func):
    def call_it(*args, **kwargs):
        """wrap func: call_it1"""
        print('before call in call_it1')
        return func(*args, **kwargs)
    return update_wrapper(call_it, func)

@wrap1
def hello1():
    """test hello 1"""
    print('hello world1')

hello1()   

def wrap3(func):
    @wraps(func)
    def call_it(*args, **kwargs):
        """wrap func: call_it3"""
        print('before call in call_it3')
        return func(*args, **kwargs)
    return call_it

@wrap3
def hello3():
    """test hello 3"""
    print('hello world3')

hello3()    

的工作。但为什么以下不是?

def wrap2(func):
    @update_wrapper(wrapped=func) # error, see below
    def call_it(*args, **kwargs):
        """wrap func: call_it2"""
        print('before call in call_it2')
        return func(*args, **kwargs)
    return call_it

@wrap2
def hello2():
    """test hello 2"""
    print('hello world2')

hello2()

有错误

TypeError: update_wrapper() missing 1 required positional argument: 'wrapper'

The declarations of wraps and update_wrapper是:

@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

位置参数wrapperupdate_wrapper的第一个参数, 那么为什么以下内容不会call_itwrapper update_wrapper提取{?1}}?

@update_wrapper(wrapped=func)
def call_it(*args, **kwargs):

有没有办法将update_wrapper用作装饰器而不是wraps

1 个答案:

答案 0 :(得分:1)

使用@作为装饰器基本上归结为:

 @(value)
 def f(...):
     ...

与以下相同:

def f(...):
    ...

f = (value)(f)

现在,如果我们将它应用于您的案例:

@update_wrapper(wrapped=func)
def call_it(*args, **kwargs):
    ...
def call_it(*args, **kwargs):
    ...

call_it = update_wrapper(wrapped=func)(call_it)

这里的问题是第一次,它只用第二个参数调用。然后它立即引发错误。

这是因为update_wrapper并非设计用作装饰器,但wraps是装饰器(工厂)。