2013-05-09 5 views
17

関数の出力をディスクに書き留める方法はありますか?ディスクにメモを付ける - Python - 永続的なメモ化

私は機能

def getHtmlOfUrl(url): 
    ... # expensive computation 

を持っているし、ような何かしたいと思います:

def getHtmlMemoized(url) = memoizeToFile(getHtmlOfUrl, "file.dat") 

をして、URLごとに一度だけ高価な計算を行うように、getHtmlMemoized(URL)を呼び出します。

+1

キャッシュディクテリストをpickle(またはjsonを使用)してください。 – root

+1

ありがとうが、私はpython初心者(2日目)です。私はあなたが何を意味するか少しだけ考えているわけではありません。 – seguso

+1

初心者は、Googleで「pickle python」を検索して、何か質問があれば私達に戻ってきます。 –

答えて

20

Pythonは、 s - デコレータ。基本的に、デコレータは、関数のソースコードを変更せずに、追加の機能を提供するために別の関数をラップする関数です。あなたはそれを持ってたら

import json 

def persist_to_file(file_name): 

    def decorator(original_func): 

     try: 
      cache = json.load(open(file_name, 'r')) 
     except (IOError, ValueError): 
      cache = {} 

     def new_func(param): 
      if param not in cache: 
       cache[param] = original_func(param) 
       json.dump(cache, open(file_name, 'w')) 
      return cache[param] 

     return new_func 

    return decorator 

、@ -syntaxを使用して機能を「飾る」とあなたは準備が整いました:あなたのデコレータは次のように書くことができます。

@persist_to_file('cache.dat') 
def html_of_url(url): 
    your function code... 

このデコレータが意図的に簡略化され、ソース関数が受け入れまたはJSONシリアライズできないデータを返すとき、例えば、すべての状況で動作しない可能性があることに注意してください。

デコレータの

より:How to make a chain of function decorators?

そして、ここでは、デコレータが終了時に、一度だけのキャッシュを保存させる方法は次のとおりです。

import json, atexit 

def persist_to_file(file_name): 

    try: 
     cache = json.load(open(file_name, 'r')) 
    except (IOError, ValueError): 
     cache = {} 

    atexit.register(lambda: json.dump(cache, open(file_name, 'w'))) 

    def decorator(func): 
     def new_func(param): 
      if param not in cache: 
       cache[param] = func(param) 
      return cache[param] 
     return new_func 

    return decorator 
+3

これは、キャッシュが更新されるたびに新しいファイルを書き込みます。これはユースケースによって異なります。あなたはmemoizationから得る.... – root

+1

それはまた、このデコレータが並行して、または(より可能性の高い)再入荷の方法で使用されている場合、非常に素晴らしい競争条件を含んでいます。 'a()'と 'b()'の両方がメモされ、 'a()'が 'b()'を呼び出すと、キャッシュは 'a()'のために読み取られ、 'b()'のために読み取られます。最初のbの結果はメモされますが、呼び出し元の古いキャッシュがそれを上書きすると、bのキャッシュへの寄与は失われます。 – SingleNegationElimination

+0

@root:確かに、 'atexit'はおそらくキャッシュをフラッシュするのに良い場所でしょう。反対に、時期尚早の最適化を追加すると、このコードの教育目的を破る可能性があります。 – georg

0

このような何かを行う必要があります。

import json 

class Memoize(object): 
    def __init__(self, func): 
     self.func = func 
     self.memo = {} 

    def load_memo(filename): 
     with open(filename) as f: 
      self.memo.update(json.load(f)) 

    def save_memo(filename): 
     with open(filename, 'w') as f: 
      json.dump(self.memo, f) 

    def __call__(self, *args): 
     if not args in self.memo: 
      self.memo[args] = self.func(*args) 
     return self.memo[args] 

基本的な使用法:

your_mem_func = Memoize(your_func) 
your_mem_func.load_memo('yourdata.json') 
# do your stuff with your_mem_func 

あなたがそれを使用した後、ファイルにあなたの「キャッシュ」を書きたい場合は - 再びロードします将来:

your_mem_func.save_memo('yournewdata.json') 
+0

それは素晴らしいですね。このクラスの使い方は?申し訳ありません... – seguso

+1

@seguso - 使用状況を更新しました。 memoizationの詳細:http://stackoverflow.com/questions/1988804/what-is-memoization-and-how-can-i-use-it-in-python – root

+0

-1不要なクラスを使用する – Merlin

11

joblib.Memoryをチェックしてください。それはまさにそれを行うためのライブラリです。

+1

コードは3行だけです! :) – Andrew

+1

うわー、どのような素晴らしい図書館!私は、これらのすべての年をjoblibなしで行ったと信じることはできません。これは正解IMOでなければなりません。 – foobarbecue

0

Artemis libraryには、このためのモジュールがあります。あなたは、あなたの関数を飾る

(あなたはpip install artemis-mlする必要があります):

from artemis.fileman.disk_memoize import memoize_to_disk 

@memoize_to_disk 
def fcn(a, b, c = None): 
    results = ... 
    return results 

は内部的には、このハッシュでメモ・ファイルの入力引数のうち、ハッシュを行い、保存します。

0

あなたのデータは、シリアライズJSONであると仮定すると、このコードは、それが以前に実行されていた場合、あなたはあなたのキャッシュされたデータを取得し、それを呼び出すだけで、その後

import os, json 

def json_file(fname): 
    def decorator(function): 
     def wrapper(*args, **kwargs): 
      if os.path.isfile(fname): 
       with open(fname, 'r') as f: 
        ret = json.load(f) 
      else: 
       with open(fname, 'w') as f: 
        ret = function(*args, **kwargs) 
        json.dump(ret, f) 
      return ret 
     return wrapper 
    return decorator 

getHtmlOfUrlを飾る仕事とすべきです。

は、Python 2.xとPythonの3.xの

0

Pythonのシェルブモジュールによって供給クリーナー液でチェック。利点は、キャッシュがリアルタイムで更新されることです。これは例外的な証明です。

import shelve 
def shelve_it(file_name): 
    d = shelve.open(file_name) 

    def decorator(func): 
     def new_func(param): 
      if param not in d: 
       d[param] = func(param) 
      return d[param] 

     return new_func 

    return decorator 

@shelve_it('cache.shelve') 
def expensive_funcion(param): 
    pass 

これにより、関数が1回だけ計算されやすくなります。次の同じパラメータの呼び出しは、格納された結果を返します。

関連する問題