8

functools.lru_cacheによって作成された部分関数のキャッシュに使用できfunctools.partialますか?

私の問題は、ハッシュ可能なパラメーターと、NumPy 配列などの定数のハッシュ不可能なオブジェクトを取る関数です。

次のおもちゃの例を考えてみましょう。

import numpy as np
from functools import lru_cache, partial

def foo(key, array):
    print('%s:' % key, array)
a = np.array([1,2,3])

NumPy 配列はハッシュ可能でないため、これは機能しません。

@lru_cache(maxsize=None)
def foo(key, array):
    print('%s:' % key, array)
foo(1, a)

予想どおり、次のエラーが表示されます。

/Users/ch/miniconda/envs/sci34/lib/python3.4/functools.py in __init__(self, tup, hash)
    349     def __init__(self, tup, hash=hash):
    350         self[:] = tup
--> 351         self.hashvalue = hash(tup)
    352 
    353     def __hash__(self):

TypeError: unhashable type: 'numpy.ndarray'

だから私の次のアイデアはfunctools.partial、NumPy配列を取り除くために使用することでした(とにかく定数です)

pfoo = partial(foo, array=a)
pfoo(2)

これで、ハッシュ可能な引数のみを受け取る関数ができましたlru_cache。しかしlru_cache、この状況で使用することは可能ですか?@lru_cacheデコレータの代わりにラッピング関数として使用することはできませんか?

これを解決する賢い方法はありますか?

4

2 に答える 2

13

配列は定数であるため、実際の lru キャッシュ関数の周りにラッパーを使用して、単純にキー値をそれに渡すことができます。

from functools import lru_cache, partial
import numpy as np


def lru_wrapper(array=None):
    @lru_cache(maxsize=None)
    def foo(key):
        return '%s:' % key, array
    return foo


arr = np.array([1, 2, 3])
func = lru_wrapper(array=arr)

for x in [0, 0, 1, 2, 2, 1, 2, 0]:
    print (func(x))

print (func.cache_info())

出力:

('0:', array([1, 2, 3]))
('0:', array([1, 2, 3]))
('1:', array([1, 2, 3]))
('2:', array([1, 2, 3]))
('2:', array([1, 2, 3]))
('1:', array([1, 2, 3]))
('2:', array([1, 2, 3]))
('0:', array([1, 2, 3]))
CacheInfo(hits=5, misses=3, maxsize=None, currsize=3)
于 2016-06-03T09:43:45.687 に答える