如何使用functools.wraps的`assigned`和`updated`参数?

7 python decorator

我知道包装的属性如下:

functools.wraps(包装[,已分配] [,已更新])

但我想知道如何使用assignedupdatedparams,有没有人有一个例子?

jsb*_*eno 5

“assigned”参数告诉包装函数上的哪些属性将分配给包装(装饰)函数上的同名属性。默认情况下,它们'__module__', '__name__', '__doc__'在变量 functools.WRAPPER_ASSIGNMENTS 中被定义为默认值。正如@abarnet 在评论中所说的那样,人们可能想要复制的另一个属性的一个示例是 Python 3.x 中的函数注释,因此您可能希望分配的参数为:('__module__', '__name__', '__doc__', '__annotations__')

“updated”参数或多或少相同,但包装器中的相应属性将使用装饰函数中的该属性调用它的“updated”方法 - 这意味着它仅在两个属性都是可变映射时才有效 - 对于例如,字典。默认情况下,这将__dict__使用被包装的 的更新包装器的属性__dict__,使包装器函数反映它可能已由不同的底层装饰器分配的所有无关属性(装饰器在调用“包装”的装饰器之前应用)被应用。更改“已更新”的唯一可能用例是将其更改为空序列,以防止__dict__从被更新。否则,如果您想更新更多属性,那将意味着您将在一个项目上工作,该项目将对可调用对象使用不同的字典属性,并且此时您肯定会遇到更多问题而不是不知道如何正确使用“包装” .

TL;DR:您可能会发现以下内容有一些用处:

@wraps(func, ('__module__', '__name__', '__doc__', '__anotations__'), ())
def wrapper(*args, **kw):
    ...
Run Code Online (Sandbox Code Playgroud)

但不一定。

最后,轶事说明,如果装饰对象是具有__call__方法的类的实例,而不是函数,则__dict__更新将使包装函数具有装饰实例的所有实例属性的副本 - 这更像是一面效果比有用的东西,因为这些复制的属性不会跟随装饰实例中状态的进一步变化(装饰实例上的方法仍将接收“self”作为解包实例):

>>> from functools import wraps
>>> class MyCallable(object):
...   def pr(self):  
...     print(self.a)
...   def __call__(self, new_a):
...     self.a =  new_a


>>> def deco(clb):
...    @wraps(clb)
...    def wrapper(*args):
...       return clb(*args)
...    return wrapper
... 
>>> m = MyCallable()
>>> m(1)
>>> m.a
1
>>> m.pr()
1
>>> m = deco(m)
>>> m(2)
>>> m.a
1
>>> m.__wrapped__.pr()
2
Run Code Online (Sandbox Code Playgroud)

因此,这可能是您不想复制__dict__到包装器,并始终通过__wrapped__属性访问原始实例的示例,如上所述。但是,我实际上离题了,因为我从来没有见过任何人用装饰器包装类的实例,并且想不出这样的用例不会通过类方法更好地解决装饰器应该做的事情。