簡體   English   中英

我可以記住Python生成器嗎?

[英]Can I memoize a Python generator?

我有一個名為runquery的函數,它調用數據庫,然后逐個生成行。 我寫了一個memoize裝飾器(或者更確切地說,我只是從這個stackoverflow問題中偷走了一個)但是在后續調用中它只產生一個空序列,大概是因為生成器的值只能產生一次。

我怎么能修改適用於Python生成器的memoization裝飾器? 我意識到我需要在某些時候將它存儲在內存中,但我想在裝飾器中處理它而不是修改原始函數。

memoization函數的當前代碼是:

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

我意識到這有點老問題,但對於那些想要完整解決方案的人來說:這是基於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
from itertools import tee

sequence, memoized_sequence = tee (sequence, 2)

完成。

對於生成器來說更容易,因為標准的lib具有這種“tee”方法!

是。 有貼裝飾這里 請注意,正如海報所說,你失去了懶惰評估的一些好處。

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

與其他答案類似,但如果您知道 f是生成器,則更簡單:

def memoized_generator(f):
    cache = {}
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        k = args, frozenset(kwargs.items())
        it = cache[k] if k in cache else f(*args, **kwargs)
        cache[k], result = itertools.tee(it)
        return result
    return wrapper

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM