I have a function called runquery
that makes calls to a database and then yields the rows, one by one. I wrote a memoize decorator (or more accurately, I just stole one from this stackoverflow question) but on subsequent calls it just yields an empty sequence, presumably because a generator's values can only be yielded once.
How could I modify the memoization decorator that works for Python generators? I realise I will need to store it in memory at some point but I'd like to handle this within the decorator and not modify the original function.
The current code of the memoization function is:
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
You can carry out the unpacking procedure for all kinds of iterables like lists, tuples, strings, iterators and generators. There are 2 ways to unpack iterables in Python. For known length iterables - Providing the exact number of variables to unpack as the number of elements in the sequence/iterable.
A Python generator is a function that produces a sequence of results. It works by maintaining its local state, so that the function can resume again exactly where it left off when called subsequent times. Thus, you can think of a generator as something like a powerful iterator.
Python Generator functions allow you to declare a function that behaves likes an iterator, allowing programmers to make an iterator in a fast, easy, and clean way. An iterator is an object that can be iterated or looped upon. It is used to abstract a container of data to make it behave like an iterable object.
I realise this is somewhat of an old question, but for those who want a full solution: here's one, based on jsbueno's suggestion:
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)
Done.
It is easier for generators because the standard lib has this "tee" method!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With