问题出在decorator
模块上。如果您print
在装饰器中添加一些语句:
from decorator import decorator
def _dynamic_programming(f, *args, **kwargs):
print "Inside decorator", id(f.cache)
try:
f.cache[args]
except KeyError:
f.cache[args] = f(*args, **kwargs)
return f.cache[args]
def dynamic_programming(f):
f.cache = {}
print "Original cache", id(f.cache)
def clear():
f.cache = {}
print "New cache", id(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)
print fib(4)
print id(fib.cache)
fib.clear()
print id(fib.cache)
print fib(10)
print id(fib.cache)
它输出(跳过重复的行):
Original cache 139877501744024
Inside decorator 139877501744024
5
139877501744024
New cache 139877501802208
139877501744024
Inside decorator 139877501802208
89
139877501744024
如您所见,cache
装饰器内部根据 clear 功能发生变化。但是,cache
访问的来源__main__
不会改变。打印cache
装饰器的外部和内部可以提供更清晰的图片(同样,跳过重复项):
Inside decorator {}
Inside decorator {(1,): 1}
Inside decorator {(2,): 2, (0,): 1, (1,): 1}
Inside decorator {(2,): 2, (0,): 1, (3,): 3, (1,): 1}
5
Outside {(2,): 2, (0,): 1, (3,): 3, (1,): 1, (4,): 5}
Inside decorator {}
Inside decorator {(1,): 1}
Inside decorator {(2,): 2, (0,): 1, (1,): 1}
Inside decorator {(2,): 2, (0,): 1, (3,): 3, (1,): 1}
Inside decorator {(2,): 2, (0,): 1, (3,): 3, (1,): 1, (4,): 5}
Inside decorator {(0,): 1, (1,): 1, (2,): 2, (3,): 3, (4,): 5, (5,): 8}
Inside decorator {(0,): 1, (1,): 1, (2,): 2, (3,): 3, (4,): 5, (5,): 8, (6,): 13}
Inside decorator {(0,): 1, (1,): 1, (2,): 2, (3,): 3, (4,): 5, (5,): 8, (6,): 13, (7,): 21}
Inside decorator {(0,): 1, (1,): 1, (2,): 2, (8,): 34, (3,): 3, (4,): 5, (5,): 8, (6,): 13, (7,): 21}
Inside decorator {(0,): 1, (1,): 1, (2,): 2, (8,): 34, (3,): 3, (9,): 55, (4,): 5, (5,): 8, (6,): 13, (7,): 21}
89
Outside {(2,): 2, (0,): 1, (3,): 3, (1,): 1, (4,): 5}
正如你所看到的,内部的变化并没有在外部得到呼应。问题是在模块decorator
内部,有一行(在它用来制作装饰器的类内部):
self.dict = func.__dict__.copy()
然后稍后:
func.__dict__ = getattr(self, 'dict', {})
所以基本上,__dict__
外面和里面是不同的__dict__
。这意味着:
- 由
__dict__
装饰器复制(未引用)
- 当
cache
改变时,它改变的是内部__dict__
,而不是外部__dict__
- 因此,被
cache
使用的_dynamic_programming
被清除了,但是从外部看不到,因为装饰器__dict__
仍然指向旧的cache
(如上所示,内部cache
更新,而外部cache
保持不变)
所以,总而言之,这是decorator
模块的问题。