functools.wraps和update_wrapper有什么区别

32 投票
2 回答
10118 浏览
提问于 2025-04-17 18:47

我找不到这两个Python函数之间的区别。

functools.wrapsupdate_wrapper

有人能给我一些代码示例,让我明白它们之间的区别吗?

2 个回答

10

通常你会使用 wraps,它是用来包装 *update_wrapper* 的。下面是一些详细信息:

  • partial 一个函数 = 创建一个新函数,并把一些参数固定为特定的值

  • wraps 会用 wrapper 来更新 *update_wrapper*,这样就创建了一个装饰器,用于 wrapper

  • *update_wrapper* 的目的是把某些属性(不是参数)从 wrapped 复制到 wrapper。默认情况下,这些属性包括:

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
                       '__annotations__')
WRAPPER_UPDATES = ('__dict__',)

一个有用的例子:

try:
    from itertools import izip_longest as zip_longest
except:
    from itertools import zip_longest
from collections import Iterable
from functools import wraps

def ziplongest(*args):
    '''zip_longest with last element as filler
    >>> args=([9],[2,3],1)
    >>> [t for t in ziplongest(*args)]
    [(9, 2, 1), (9, 3, 1)]

    '''
    iterable = lambda a:(a if isinstance(a,Iterable) else [a])
    _args = [iterable(a) for a in args]
    withnone = zip_longest(*_args)
    for e in withnone:
        yield tuple((en or _args[i][-1]) for i,en in enumerate(e))

def listable(f):
    '''apply f to list members
    >>> @listable
    ... def mul(a,b):
    ...     'returns a*b'
    ...     return a*b
    >>> mul(2,[3,9])
    [6, 18]
    >>> mul.__doc__
    'returns a*b'

    '''
    @wraps(f)#without this e.g __doc__ would get hidden
    def to_elems(*args,**kwargs):
        if any(isinstance(x,list) for x in args):
            return [f(*a,**kwargs) for a in ziplongest(*args)]
        else:
            return f(*args,**kwargs)
    return to_elems
25

functools.wraps 的作用和下面的内容是一样的:

def wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES):
    def decorator(wrapper):
        return update_wrapper(wrapper, wrapped=wrapped, ...)
    return decorator

它实际上是用 partial 来实现的,而不是用内部函数,但效果是一样的。

它的目的是为了让我们可以把它当作装饰器来使用:

 @wraps(f)
 def g():
     ...

这和下面的内容是等价的:

def g():
    ...
g = update_wrapper(g, f)

撰写回答