我有一个简单的小装饰器,它将dict
中函数调用的结果缓存为函数属性。你知道吗
from decorator import decorator
def _dynamic_programming(f, *args, **kwargs):
try:
f.cache[args]
except KeyError:
f.cache[args] = f(*args, **kwargs)
return f.cache[args]
def dynamic_programming(f):
f.cache = {}
return decorator(_dynamic_programming, f)
我现在想添加清空缓存的可能性。所以我把dynamic_programming()
函数改成这样:
def dynamic_programming(f):
f.cache = {}
def clear():
f.cache = {}
f.clear = clear
return decorator(_dynamic_programming, f)
现在假设我用这个小东西来实现一个斐波那契数函数:
@dynamic_programming
def fib(n):
if n <= 1:
return 1
else:
return fib(n-1) + fib(n-2)
>>> fib(4)
5
>>> fib.cache
{(0,): 1, (1,): 1, (2,): 2, (3,): 3, (4,): 5}
但现在当我清除缓存时,奇怪的事情发生了:
>>> fib.clear()
>>> fib.cache
{(0,): 1, (1,): 1, (2,): 2, (3,): 3, (4,): 5}
或者(在运行新的Python内核的情况下)用另一种方法:
>>> fib.clear()
>>> fib(4)
5
>>> fib.cache
{}
为什么缓存在第一次访问后就不“可访问”,即在调用后调用clear()
或在调用后调用clear()
时不更改?你知道吗
(顺便说一句,我知道一个正确清除缓存的解决方案:调用f.cache.clear()
,而不是将{}
分配给它,效果与预期一样。我只对赋值解失败的原因感兴趣。)
问题在于
decorator
模块。如果将一些print
语句添加到decorator中:它输出(跳过重复行):
如您所见,decorator中的
cache
会根据clear函数的不同而变化。但是,从__main__
访问的cache
没有改变。在decorator内外打印cache
可以获得更清晰的图像(同样,跳过了重复项):正如你所看到的,内部的变化并没有在外部得到回应。问题是在the ^{} module 中有一行(在它用来生成decorator的类中):
然后later:
所以基本上,外面的
__dict__
和里面的__dict__
是不同的。这意味着:__dict__
被装饰器复制(没有引用)cache
改变时,它改变的是内部__dict__
,而不是外部__dict__
_dynamic_programming
使用的cache
被清除,但是您无法从外部看到,因为装饰器的__dict__
仍然指向旧的cache
(正如您在上面看到的,由于内部cache
更新,而外部cache
保持不变)总之,
decorator
模块有问题。你知道吗所以@matsjoyce的答案非常有趣和深入,我知道你已经有了解决方案,但我总是觉得写我自己的decorators会更清楚一些:
相关问题 更多 >
编程相关推荐