def mygen():
while True:
print __self__.data
yield None g = mygen()
g.data = 1
g.next() # prints 1
g.data = 2
g.next() # prints 2I looked in the archives but couldn't find a good discussion of why setting an attribute on the generator is preferable to passing the argument to next. Isn't this example basically equivalent to:
class mygen(object):
def next(self, data):
print data
return None g = mygen()
g.next(1) # prints 1
g.next(2) # prints 2Note that I didn't even define an __iter__ method since it's never used in the example.
Another example from the PEP:
def filelike(packagename, appendOrOverwrite):
data = []
if appendOrOverwrite == 'w+':
data.extend(packages[packagename])
try:
while True:
data.append(__self__.dat)
yield None
except FlushStream:
packages[packagename] = data ostream = filelike('mydest','w')
ostream.dat = firstdat; ostream.next()
ostream.dat = firstdat; ostream.next()
ostream.throw(FlushStream)This could be rewritten as:
class filelike(object):
def __init__(self, packagename, appendOrOverwrite):
self.data = []
if appendOrOverwrite == 'w+':
self.data.extend(packages[packagename])
def next(self, dat):
self.data.append(dat)
return None
def close(self):
packages[packagename] = self.data ostream = filelike('mydest','w')
ostream.next(firstdat)
ostream.next(firstdat)
ostream.close()So, I guess I have two questions:
(1) What's the benefit of the generator versions of these functions over the class-based versions?
(2) Since in all the examples there's a one-to-one correlation between setting a generator attribute and calling the generator's next function, aren't these generator attribute assignments basically just trying to define the 'next' parameter list?
If this is true, I would have expected that a more useful idiom would look something like:
def mygen():
while True:
data, = nextargs()
print data
yield None g = mygen()
g.next(1) # prints 1
g.next(2) # prints 2where the nextargs function retrieves the arguments of the most recent call to the generator's next function.
With a little sys._getframe hack, you can basically get this behavior now:
py> class gen(object): ... def __init__(self, gen): ... self.gen = gen ... def __iter__(self): ... return self ... def next(self, *args): ... return self.gen.next() ... @staticmethod ... def nextargs(): ... return sys._getframe(2).f_locals['args'] ... py> def mygen(): ... while True: ... data, = gen.nextargs() ... print data ... yield None ... py> g = gen(mygen()) py> g.next(1) 1 py> g.next(2) 2
Of course, it's still a little magical, but I think I like it a little better because you can see, looking only at 'mygen', when 'data' is likely to change value...
Steve
[1] http://www.python.org/peps/pep-0288.html -- http://mail.python.org/mailman/listinfo/python-list
