我遇到了一个特殊的行为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")
Run Code Online (Sandbox Code Playgroud)
这个例子按预期工作 - 它的输出是
Retrieving from memory
Retrieving from disk
expensive_function working on Expensive Calculation
Run Code Online (Sandbox Code Playgroud)
然而,我花了很长时间才完成这项工作 - 起初,我没有在 functools.update_wrapper 调用中包含 'updated=()' 参数。但是,当忽略这一点时,嵌套装饰器将不起作用 - 在这种情况下,输出是
Retrieving from memory
expensive_function working on Expensive Calculation
Run Code Online (Sandbox Code Playgroud)
即外层装饰器直接调用最内层包装函数。原因(我花了一段时间才理解)是将包装器的属性 …