4

関数のラッピングに渡される変数を実際に使用する関数パラメーターを持つデコレーターを作成する方法を探しています。

たとえば、私が持っているとしましょう

@cache_decorator("my_key_{}".format(foo))
def my_function(foo, bar):
    pass

@cache_decorator("another_key_{}_{}".format(foo, bar)
def another_function(user, foo, bar):
    pass

目標は、キャッシング ラッパーを作成することです。デコレータはキャッシュ キーを必要としますが、キーには関数に渡される変数が含まれ、ラップする関数ごとに異なります。

理想的には、これによりデコレータは特定のキーのキャッシュされた値をチェックし、見つからない場合は関数を実行して値を取得し、キャッシュします。そうすれば、値がキャッシュにある場合、値を作成するコード (つまり my_function) は実行されません。見つからない場合は my_function を実行し、結果をキャッシュに保存して返します。

別の代替手段は、ブロックに似たものになります。

def my_function(foo, bar):
    cache_value("my_key_{}".format(foo),{block of code to generate value that is only called if necessary})

Objective-C または js では、これはブロックになるため、値の生成をローカルで定義して変更可能にしておくことができますが、必要な場合にのみ実行されます。私はPythonに慣れていないので、クロージャーのバージョンでこれを行う方法を完全に把握できません。

ありがとう!

更新
以下のソリューションはデコレータに対して機能しましたが、適切に無効化できるようにするために各キャッシュ エントリに追加のメタデータをアタッチする必要があるため、最終的にブロックのようなルートに行きました。このメタデータを (キャッシュ関数内ではなく) 値の生成で定義すると、保守が容易になります。これは次のようになります。

def my_function(foo, bar):
    def value_func():
        return code_to_generate_value_using_foo_bar

    return get_set_cache(key, value_func, ...)

def get_set_cache(key, value_function, ...):
    value = cache.get(key)
    if value is None:
        value = value_function()
        cache.set(key, value)
    return value
4

3 に答える 3

3

ラッパーに主要な構築関数を取得させることができます。

@cache_w_keyfunc(lambda foo, bar: (bar,))
def my_function(foo, bar):
    pass

@cache_w_keyfunc(lambda user, foo, bar: (foo, bar))
def another_function(user, foo, bar):
    pass

キー ビルダーは、文字列のタプルなど、ハッシュ可能なものを返す必要があります。リストなど、ハッシュ可能でない場合は、文字列に変換してください。

このキー構築関数は、関数自体と同じ引数を取得し、使用するキーを返します。

def cache_w_keyfunc(keyfunc):
    def real_decorator(func):
        func.cache = {}
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # Create the key now out of the wrapped function's name and the given keys:
            key = (func.__name__, keyfunc(*args, **kwargs))
            try:
                return func.cache[cache_key]
            except KeyError:
                value = func(*args, **kwargs)
                func.cache.set(cache_key, value)
                return value
        return wrapper
    return real_decorator
于 2013-09-28T13:24:19.630 に答える
1

見たことがありますdogpile.cacheか?

まさにこれを行うキャッシングシステムです。

ドッグパイルを使用できる場合があります。そうでない場合は、そのソースを見て、それがどのように機能するかを正確に確認できます。

ついでに言うと、dogpile.cache は、あなたが気にするべき小さな詳細をすべて処理します:

  • キーを別々に保つ
  • シリアライズ/デシリアライズ
  • 値の有効期限と再検証
  • キャッシュのヒットとミスの処理
于 2013-09-13T16:52:39.347 に答える