23

runqueryデータベースを呼び出してから行を 1 つずつ生成するという関数があります。memoize デコレータを作成しました (または、より正確には、この stackoverflow questionから 1 つ盗みました) が、その後の呼び出しでは、おそらくジェネレータの値を 1 回しか生成できないため、空のシーケンスが生成されます。

Python ジェネレーターで機能するメモ化デコレーターを変更するにはどうすればよいですか? ある時点でメモリに保存する必要があることはわかっていますが、これをデコレータ内で処理し、元の関数を変更したくありません。

メモ化関数の現在のコードは次のとおりです。

def memoized(f):
    # Warning: Doesn't work if f yields values
    cache={}
    def ret(*args):
        if args in cache:
            return cache[args]
        else:
            answer=f(*args)
            cache[args]=answer
            return answer
    return ret
4

4 に答える 4

21

これはやや古い質問だと思いますが、完全な解決策が必要な人のために: jsbueno の提案に基づいたものを次に示します。

from itertools import tee
from types import GeneratorType

Tee = tee([], 1)[0].__class__

def memoized(f):
    cache={}
    def ret(*args):
        if args not in cache:
            cache[args]=f(*args)
        if isinstance(cache[args], (GeneratorType, Tee)):
            # the original can't be used any more,
            # so we need to change the cache as well
            cache[args], r = tee(cache[args])
            return r
        return cache[args]
    return ret
于 2012-05-23T19:11:16.363 に答える
10
from itertools import tee

sequence, memoized_sequence = tee (sequence, 2)

終わり。

標準ライブラリにはこの「tee」メソッドがあるため、ジェネレーターの方が簡単です。

于 2010-12-30T22:53:42.613 に答える
4

はい。hereに投稿されたデコレータがあります。ポスターが言うように、遅延評価の利点の一部が失われることに注意してください。

def memoize(func):
    def inner(arg):
        if isinstance(arg, list):
            # Make arg immutable
            arg = tuple(arg)
        if arg in inner.cache:
            print "Using cache for %s" % repr(arg)
            for i in inner.cache[arg]:
                yield i
        else:
            print "Building new for %s" % repr(arg)
            temp = []
            for i in func(arg):
                temp.append(i)
                yield i
            inner.cache[arg] = temp
    inner.cache = {}
    return inner


@memoize
def gen(x):
    if not x:
        yield 0
        return

    for i in xrange(len(x)):
        for a in gen(x[i + 1:]):
            yield a + x[0]


print "Round 1"
for a in gen([2, 3, 4, 5]):
    print a

print
print "Round 2"
for a in gen([2, 3, 4, 5]):
    print a
于 2010-12-30T22:33:56.463 に答える