web-dev-qa-db-ja.com

ディスクにメモ化-python-永続的なメモ化

関数の出力をディスクにメモ化する方法はありますか?

機能があります

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

そして、次のようなことをしたいと思います:

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

次に、getHtmlMemoized(url)を呼び出して、URLごとに1回だけ高価な計算を実行します。

30
seguso

Pythonはこれを行う非常にエレガントな方法を提供します-デコレータ。基本的に、デコレータは、関数のソースコードを変更せずに、別の関数をラップして追加の機能を提供する関数です。デコレータは次のように書くことができます:

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シリアル化できないデータを受け入れたり返したりする場合など、すべての状況で機能するとは限らないことに注意してください。

デコレータの詳細: 関数デコレータのチェーンを作成する方法は?

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

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
26
georg

チェックアウト - joblib.Memory 。それはまさにそれを行うためのライブラリです。

17
Will

PythonのShelveモジュールを利用したよりクリーンなソリューション。利点は、キャッシュがよく知られているdict構文を介してリアルタイムで更新されることです。また、例外の証拠でもあります(煩わしいKeyErrorを処理する必要はありません)。

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回だけ計算できるようになります。次の後続の呼び出しは、保存された結果を返します。

3
nehemiah

Artemisライブラリ にはこのためのモジュールがあります。 (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

内部的には、入力引数からハッシュを作成し、このハッシュによってメモファイルを保存します。

2
Peter

diskcache もあります。

from diskcache import Cache

cache = Cache("cachedir")

@cache.memoize()
def f(x, y):
    print('Running f({}, {})'.format(x, y))
    return x, y
0
C. Yduqoli

データが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
Uri Goren

Cache_to_diskパッケージを使用できます。

    from cache_to_disk import cache_to_disk

    @cache_to_disk(3)
    def my_func(a, b, c, d=None):
        results = ...
        return results

これにより、引数a、b、c、およびdに固有の結果が3日間キャッシュされます。結果はマシンのピクルスファイルに保存され、次に関数が呼び出されたときにピクルスが解除されて返されます。 3日後、関数が再実行されるまで、pickleファイルは削除されます。関数が新しい引数で呼び出されるたびに、関数は再実行されます。詳細はこちら: https://github.com/sarenehan/cache_to_disk

0
Stewart Renehan

このようなことをする必要があります:

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

"cache"を使用後にファイルに書き込みたい場合は、後で再度ロードします。

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