>我遇到了一个特殊的functools.update_wrapper
行为:它用包装对象的__dict__
覆盖了包装对象 - 这可能会阻碍它在嵌套装饰器时使用。
举一个简单的例子,假设我们正在编写一个在内存中缓存数据的装饰器类和另一个将数据缓存到文件的装饰器类。下面的示例演示了这一点(我使示例简短并省略了所有缓存逻辑,但我希望它演示了这个问题):
import functools
class cached:
cache_type = 'memory'
def __init__(self, fcn):
super().__init__()
self.fcn = fcn
functools.update_wrapper(self, fcn, updated=())
def __call__(self, *args):
print("Retrieving from", type(self).cache_type)
return self.fcn(*args)
class diskcached(cached):
cache_type = 'disk'
@cached
@diskcached
def expensive_function(what):
print("expensive_function working on", what)
expensive_function("Expensive Calculation")
此示例按预期工作 - 其输出为
Retrieving from memory
Retrieving from disk
expensive_function working on Expensive Calculation
然而,我花了很长时间来完成这项工作 - 起初,我没有在functools.update_wrapper调用中包含"update=()"参数。但是当它被排除在外时,嵌套装饰器不起作用 - 在这种情况下,输出是
Retrieving from memory
expensive_function working on Expensive Calculation
即外部装饰器直接调用最里面的包装函数。这样做的原因(我花了一段时间才理解)是functools.update_wrapper
将包装器的__dict__
属性更新为包装参数的__dict__
属性 - 这会缩短内部装饰器,除非添加updated=()
参数。
我的问题是:这种行为是有意的吗——为什么?(蟒蛇 3.7.1)
使包装函数看起来像它包装的函数是update_wrapper
的重点,其中包括__dict__
条目。它不会取代__dict__
;它称update
.
如果update_wrapper
没有这样做,那么如果一个装饰器在函数上设置属性,而另一个装饰器包装修改后的函数:
@decorator_with_update_wrapper
@decorator_that_sets_attributes
def f(...):
...
包装器函数不会设置属性,使其与查找这些属性的代码不兼容。