[英]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.