gpt4 book ai didi

python - 为什么 functools.update_wrapper 会更新 wrapper 对象中的 __dict__?

转载 作者:行者123 更新时间:2023-11-28 22:13:58 31 4
gpt4 key购买 nike

我遇到了 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 调用中包含“updated=()”参数。但是当这个被遗漏时,嵌套装饰器就不起作用了——在这种情况下,输出是

Retrieving from memory
expensive_function working on Expensive Calculation

即外层装饰器直接调用最内层的包装函数。原因(我花了一段时间才明白)是 functools.update_wrapper更新 __dict__包装器的属性到 __dict__包装参数的属性 - 使内部装饰器短路,除非添加 updated=()争论。

我的问题:这种行为是故意的吗?为什么? ( python 3.7.1)

最佳答案

使包装函数看起来像它包装的函数是 update_wrapper 的要点,它包括 __dict__ 条目。它不会取代 __dict__;它调用 update

如果 update_wrapper 没有这样做,那么如果一个装饰器在函数上设置属性,而另一个装饰器包装修改后的函数:

@decorator_with_update_wrapper
@decorator_that_sets_attributes
def f(...):
...

包装函数不会设置属性,使其与查找这些属性的代码不兼容。

关于python - 为什么 functools.update_wrapper 会更新 wrapper 对象中的 __dict__?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53602825/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com