1

ここの memoize レシピを使用しており、2 つの値を返す関数用に少し変更しています。このラッパーを使用して、1 番目と 2 番目の値を個別に返す 2 つの別個の関数を作成しますが、返された関数のいずれかが同じ引数で呼び出されたときにオーバーヘッドが発生しないように、関数の評価はキャッシュされます。このラッパーのコードは次のとおりです。

def memoize(obj, cache_limit=10):
    '''
    This function caches the return value each time it is called. partial() is used to return the appropriate value.
    Cache size is limited to 10
    See here for details on this design pattern: https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
    '''
    cache = obj.cache = {}
    key_cache = collections.deque()

    @functools.wraps(obj)
    def memoizer(which, *args, **kwargs):
        key = str(args)
        if key not in cache:
            cache[key] = obj(*args, **kwargs)
            key_cache.append(key)
            if len(key_cache) >= cache_limit:
                del cache[key_cache.popleft()]
        return cache[key][which]
    return functools.partial(memoizer, 0), functools.partial(memoizer, 1)

今、私はfこのようにクラスで定義されている関数でこれを使用しようとしています:

class test_function:
    def __init__(self):
        ''''''

    def f(self,x):
        return 2*x, 3*x

そして、私はそれをこのように呼んでいます

a = test_function()
f_v1, f_v2 = memoize(a.f)

成功するとf_v1(x)が返さ2xれ、f_v2(x)が返され3xます。しかし、これはエラーで失敗します:

AttributeError: 'instancemethod' object has no attribute 'cache'

関数がクラス外で宣言されている場合、私のコードは正常に動作します。私は何が欠けていますか?を使用してPython 2.7います。

4

1 に答える 1

2

メソッドは、関数とは異なる種類のオブジェクトです (instancemethodエラー メッセージが示すように、オブジェクトです。この型は として利用できますtypes.MethodType)。関数オブジェクトとは異なり、インスタンス メソッドには がない__dict__ため、それらに任意の属性を設定することはできません。obj.someMethod.someAttribute = "blah"メソッドで呼び出される独自のカスタム属性を作成することはできませんsomeAttribute

そこから実際にアクセスすることはないので、とにかくオブジェクトにキャッシュを保存している理由は明確ではありません。ローカル変数のみを使用するcacheと、クロージャーに保存され、正常に動作します。

def memoize(obj, cache_limit=10):
    '''
    This function caches the return value each time it is called. partial() is used to return the appropriate value.
    Cache size is limited to 10
    See here for details on this design pattern: https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
    '''
    cache = {}
    key_cache = collections.deque()

    @functools.wraps(obj)
    def memoizer(which, *args, **kwargs):
        key = str(args)
        if key not in cache:
            cache[key] = obj(*args, **kwargs)
            key_cache.append(key)
            if len(key_cache) >= cache_limit:
                del cache[key_cache.popleft()]
        return cache[key][which]
    return functools.partial(memoizer, 0), functools.partial(memoizer, 1)

>>> a = test_function()
... f_v1, f_v2 = memoize(a.f)
>>> f_v1(2)
4
>>> f_v2(2)
6
于 2015-02-24T19:30:37.117 に答える