我有一个名为runquery
的函数,它调用数据库,然后一个接一个地生成行。我写了一个memoize装饰器(或者更准确地说,我只是从this stackoverflow question那里偷来了一个),但在随后的调用中,它只会产生一个空序列,可能是因为生成器的值只能生成一次。
如何修改适用于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
发布于 2012-05-24 03:11:16
我意识到这是一个老问题,但对于那些想要完整解决方案的人来说:这里有一个,基于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
发布于 2010-12-31 06:53:43
from itertools import tee
sequence, memoized_sequence = tee (sequence, 2)
好了。
这对于生成器来说更容易,因为标准库有这个"tee“方法!
发布于 2010-12-31 06:33:56
是。有一个装饰师张贴着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
https://stackoverflow.com/questions/4566769
复制相似问题