問題は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
モジュールの問題です。