_cachedf関数が返された後も、キャッシュ変数がどのように存在するかを理解するのを手伝ってもらえますか?
これは、Pythonの参照カウントガベージコレクターと関係があります。関数には変数への参照があり、呼び出し元には変数への参照があるcache
ため、変数は保存されてアクセス可能になります。関数を再度呼び出すと、最初に作成されたものと同じ関数オブジェクトを使用しているため、キャッシュにアクセスできます。_cachedf
cached
キャッシュへのすべての参照が破棄されるまで、キャッシュが失われることはありません。del
演算子を使用してそれを行うことができます。
例えば:
>>> import time
>>> def cached(f):
... cache = {} # <---- not an attribute this time!
... def _cachedf(*args):
... if args not in cache:
... cache[args] = f(*args)
... return cache[args]
... return _cachedf
...
...
>>> def foo(duration):
... time.sleep(duration)
... return True
...
...
>>> bob = cached(foo)
>>> bob(2) # Takes two seconds
True
>>> bob(2) # returns instantly
True
>>> del bob # Deletes reference to bob (aka _cachedf) which holds ref to cache
>>> bob = cached(foo)
>>> bob(2) # takes two seconds
True
>>>
記録のために、あなたが達成しようとしているのはメモ化と呼ばれ、同じことをしますが、デコレータクラスを使用する、より完全なメモ化デコレータがデコレータパターンページから入手できます。コードとクラスベースのデコレータは基本的に同じですが、クラスベースのデコレータは保存する前にハッシュ能力をチェックします。
編集(2017-02-02):@SiminJieのコメントは、cached(foo)(2)
常に遅延が発生します。
これはcached(foo)
、新しいキャッシュを持つ新しい関数を返すためです。がcached(foo)(2)
呼び出されると、新しい新しい(空の)キャッシュが作成され、キャッシュされた関数がすぐに呼び出されます。
キャッシュは空であり、値が見つからないため、基になる関数を再実行します。代わりに、実行してから複数回cached_foo = cached(foo)
呼び出します。cached_foo(2)
これにより、最初の呼び出しの遅延のみが発生します。また、デコレータとして使用すると、期待どおりに機能します。
@cached
def my_long_function(arg1, arg2):
return long_operation(arg1,arg2)
my_long_function(1,2) # incurs delay
my_long_function(1,2) # doesn't
デコレータに慣れていない場合は、この回答を見て、上記のコードの意味を理解してください。