Callable generators (PEP 288: Generator Attributes, again)
Greg Chapman
glc at well.com
Wed Nov 19 13:24:20 EST 2003
On 18 Nov 2003 02:11:48 -0800, francisgavila at yahoo.com (Francis Avila) wrote:
>Personally, I'd like to one day be able to do stupid things like this:
>>>> e = echo()
>>>> tuple(feed(e, xrange(5))
>(0, 1, 2, 3, 4)
Here's one way of getting a resumable function with parameters:
def echo(defvalue = 1):
def gen():
args = [None]
def callgen(arg=defvalue):
args[0] = arg
return gennext()
yield callgen
while True:
value, = args
yield value
gennext = gen().next
return gennext()
You can elaborate on this by abstracting out the generator caller (callgen) with
something like the following (which also allows throwing an exception into a
generator, provided the generator adheres to the convention of unpacking its
arguments when resumed from a yield):
class GenArgs(object):
def __init__(self):
self.args = ()
self.exc = None
def __iter__(self):
if self.exc:
raise self.exc
return iter(self.args)
def __call__(self):
if self.exc:
raise self.exc
return self.args
class CallGen(object):
def __init__(self, gen, genargs, numargs, defaults):
assert numargs >= 0 and len(defaults) <= numargs
self.gen = gen
self.gennext = gen.next
self.genargs = genargs
self.numargs = numargs
self.defaults = defaults
def __call__(self, *cargs):
numargs = self.numargs
numcargs = len(cargs)
if numcargs < numargs:
diff = numargs-numcargs
defaults = self.defaults
if diff <= len(defaults):
cargs = cargs+defaults[-diff:]
numcargs = numargs
if numargs != numcargs:
raise TypeError('%s takes %d arguments (%d given)' % (
self.gen.gi_frame.f_code.co_name, numargs, numcargs
))
self.genargs.args = cargs
return self.gennext()
def throw(self, exc):
self.genargs.exc = exc
try:
return self.gennext()
except StopIteration:
return None
def makeCallGen(gen, numargs, defaults=()):
genargs = GenArgs()
return CallGen(gen, genargs, numargs, defaults), genargs
# Here's echo again with the above:
def echo(defvalue=1):
def gen():
while True:
value, = args
yield value
callgen, args = makeCallGen(gen(), 1, (defvalue,))
return callgen
---
Greg Chapman
More information about the Python-list
mailing list