web-dev-qa-db-ja.com

PythonインスタンスごとのLRUキャッシュデコレータ

ここにあるLRUキャッシュデコレータの使用: http://code.activestate.com/recipes/578078-py26-and-py30-backport-of-python-33s-lru-cache/

from lru_cache import lru_cache
class Test:
    @lru_cache(maxsize=16)
    def cached_method(self, x):
         return x + 5

これで装飾されたクラスメソッドを作成できますが、最終的にはクラスTestのallインスタンスに適用されるグローバルキャッシュが作成されます。ただし、私の意図は、インスタンスごとのキャッシュを作成することでした。したがって、3つのテストをインスタンス化する場合、3つのインスタンスすべてに対して1つのLRUキャッシュではなく、3つのLRUキャッシュがあります。

これが発生していることを示す唯一の兆候は、異なるクラスインスタンスで装飾されたメソッドでcache_info()を呼び出すと、すべて同じキャッシュ統計が返されます(非常に異なる引数と相互作用しているため、発生する可能性は非常に低いです)。

CacheInfo(hits=8379, misses=759, maxsize=128, currsize=128)
CacheInfo(hits=8379, misses=759, maxsize=128, currsize=128)
CacheInfo(hits=8379, misses=759, maxsize=128, currsize=128)

このデコレータに各クラスインスタンスのキャッシュを簡単に作成させるデコレータまたはトリックはありますか?

36
crzysdrs

コードを変更したくないと仮定します(たとえば、3.3に移植して、stdlibを使用できるようにしたいため functools.lru_cache 、または functools32 レシピをコピーしてコードに貼り付ける代わりにPyPIから)、1つの明白な解決策があります:各インスタンスで新しい装飾されたインスタンスメソッドを作成します。

class Test:
    def cached_method(self, x):
         return x + 5
    def __init__(self):
         self.cached_method = lru_cache(maxsize=16)(self.cached_method)
47
abarnert

最近では、methodtoolsが機能します

from methodtools import lru_cache
class Test:
    @lru_cache(maxsize=16)
    def cached_method(self, x):
         return x + 5

Methodtoolsをインストールする必要があります

pip install methodtools

まだpy2を使用している場合は、functools32も必要です

pip install functools32
2
youknowone

これはどうですか:methodlru_cacheでラップするfunctionデコレータ各インスタンスで初めて呼び出されますか?

def instance_method_lru_cache(*cache_args, **cache_kwargs):
    def cache_decorator(func):
        @wraps(func)
        def cache_factory(self, *args, **kwargs):
            print('creating cache')
            instance_cache = lru_cache(*cache_args, **cache_kwargs)(func)
            instance_cache = instance_cache.__get__(self, self.__class__)
            setattr(self, func.__name__, instance_cache)
            return instance_cache(*args, **kwargs)
        return cache_factory
    return cache_decorator

次のように使用します。

class Foo:
    @instance_method_lru_cache()
    def times_2(self, bar):
        return bar * 2

foo1 = Foo()
foo2 = Foo()

print(foo1.times_2(2))
# creating cache
# 4
foo1.times_2(2)
# 4

print(foo2.times_2(2))
# creating cache
# 4
foo2.times_2(2)
# 4

GitHubの要点です いくつかのインラインドキュメントがあります。

2
z0r