2013-03-23 9 views
11

私は@functools.lru_cacheをPython 3.3で使用しています。私はプログラムを再起動するときにそれを復元するために、ファイルにキャッシュを保存したいと思います。どうすればいいですか?キャッシュをファイルに保存するfunctools.lru_cache in Python> = 3.2

編集1考えられる解決策:__closure__を酸洗We need to pickle any sort of callable

問題:

_pickle.PicklingError: Can't pickle <class 'cell'>: attribute lookup builtins.cell failed 

私はそれなしで機能を回復しようとすると、私が手:

TypeError: arg 5 (closure) must be tuple 
+4

注意を私のライブラリを使用することができますおそらく未来を保証するものではないでしょう。 –

+0

@MartijnPieters:情報をありがとう。 –

+2

'lru_cache'を避けてください。あなたの関数が 'lru_cache'を持つことが重要か、単純なキャッシュで十分ですか?それ以外の場合は、 'lru_cache'を再実装して、必要な機能を追加することができます。 – Bakuriu

答えて

10

lru_cacheは、キャッシュにアクセスするためのAPIを提供していないため、今後のリリースではC言語で書き直される可能性があります。キャッシュを本当に保存したい場合は、キャッシュにアクセスできる別のソリューションを使用する必要があります。

自分でキャッシュを書き込むだけで簡単です。たとえば:

>>> @cached 
... def fibonacci(n): 
...  if n < 2: 
...    return n 
...  return fibonacci(n-1) + fibonacci(n-2) 
... 
>>> fibonacci(100) 
354224848179261915075L 

そしてcacheを取得する:あなたはその後、デコレータとしてそれを適用することができます

from functools import wraps 

def cached(func): 
    @wraps(func) 
    def wrapper(*args): 
     try: 
      return func.cache[args] 
     except KeyError: 
      func.cache[args] = result = func(*args) 
      return result 
    wrapper.cache = {} 
    return wrapper 

あなたが喜ばとして

>>> fibonacci.cache 
{(32,): 2178309, (23,): 28657, ... } 

その後、漬物/キャッシュをunpickle化することができますし、読み込み:

fibonacci.cache = pickle.load(cache_file_object) 

は、ダンプ/ロードをlru_cacheに追加するためにpythonの問題追跡ツールで見つかりましたが、受け入れられなかった/実装されていませんでした。将来的には、lru_cacheを介してこれらの操作の組み込みサポートを組み込むことが可能になります。

+1

コードをありがとう、私はそれを試してみる、私はそれが良い解決策かもしれないと思う。 私は機能リクエストの作成者です;)日付を見てください。 –

+0

正確なユースケースに応じて、[shelves](https://docs.python.org/3.5/library/shelve.html)でキャッシュを構築する価値がありますが、これは基本的に永続性のあるdictです。 –

+0

これは実際には機能しません! pickleを使ってキャッシュをディスクに保存することはできますが、前述のようにロードすることはできません。 – Nudin

1

あなたはありませんパブリックAPIを除いてデコレータ実装内のものに触れているはずですその動作を変更したい場合は、実装をコピーして必要な機能を自分で追加する必要があります。キャッシュは現在、循環的な二重リンクリストとして保存されているため、保存してロードする際には注意が必要です。

+0

内部はかなりトリッキーです。私はそれらを編集してキャッシュを公開することができますが、可能であれば、デフォルトのライブラリを変更しないことを好みます。 –

+0

@FrancescoFrassinelli私はあなたがあなたのプロジェクトに実装をコピーして変更できることを意味しました。 – wRAR

+0

はい、私はそれを得ました。関数をエクスポートする(marshal?)またはキャッシュをエクスポートしてインポートする(inspect?)方法はありません。 –

4

ディスクに永続的にキャッシュするには、joblib.Memoryを使用することを検討してください。

ディスクが膨大なので、LRUキャッシング方式は必要ありません。

1

あなたは、私はLRUキャッシュ実装は、Python 3.4または3.5でのCの実装に置き換えることになるだろう、キャッシュの内容を抽出するのいずれかの試みがあると思いmezmorize

import random 
from mezmorize import Cache 

cache = Cache(CACHE_TYPE='filesystem', CACHE_DIR='cache') 


@cache.memoize() 
def add(a, b): 
    return a + b + random.randrange(0, 1000) 

>>> add(2, 5) 
727 
>>> add(2, 5) 
727 
+1

うまく動作しますが、「CACHE_DIRの周りにはありません。残念ながら、編集は少なくとも6文字でのみ可能です.... – koalo