[Python-Dev] code blocks using 'for' loops and generators
Brian Sabbey
sabbey at u.washington.edu
Sun Mar 13 00:54:06 CET 2005
On Sat, 12 Mar 2005, Steven Bethard wrote:
> The goals behind this seem a lot like the goals of PEP 288[1]. I
> remember discussions suggesting code like:
>
> def gen():
> a, b, c=3 = yield 1
> yield a + b*c
>
> g = gen()
> print g.next() # prints 1
> print g.next(1, 2) # prints 7
>
> But as you can see, this creates a weird asymmetry because the last
> yield throws away its arguments, and depending on how the generator is
> written, different calls to next may require a different number of
> arguments. This means that, unless the code is extremely well
> documented, you have to read the source code for the generator to know
> how to call it.
The intention of my proposal was for using generators with 'for' loops.
In this case, the generator runs to completion, so the arguments to the
last yield are never thrown away. If 'next' were not able to take any
arguments, that would be compatible with my proposal.
Also, there was the issue that there is an asymmetry because the first
call to 'next' does not take any arguments. This asymmetry does not
exist, however, when using the generator in a 'for' loop, because there is
no "first" call to 'continue' in such a case.
> Because of these and other complications, I believe the PEP is now
> lobbying for a way to get the generator instance object and a way to
> cause an exception to be thrown from outside the generator. Take a
> look and see if the PEP might meet your needs -- I haven't seen much
> action on it recently, but it seems much less invasive than your
> proposal...
This PEP solves similar problems, yes. And I would agree that my proposal
is much more invasive on python's implementation. From the users' point
of view, however, I think it is much less invasive. For example, no doubt
there will be many users who write a generator that is to be used in a
'for' loop and are baffled that they receive a syntax error when they try
to write some try/finally cleanup code. With the PEP, they would have to
figure out that they have to use the 'throw' method of generators to
trigger cleanup code (and then have to remember to call it each time they
are done with the generator). With this proposal, try/finally would just
work as they expect and they would be non the wiser.
> def pickled_file(name):
> self = mygen.get_instance()
> f = open(name, 'r')
> yield pickle.load(f)
> f.close()
> f = open(name, 'w')
> pickle.dump(self.l, f)
> f.close()
>
> And this would be written something like:
>
> gen = pickled_file('greetings.pickle')
> for l in gen:
> l.append('hello')
> l.append('howdy')
> gen.l = l
>
> Personally, I find this use of a generator thoroughly confusing, and I
> don't see what you gain from it. The PEP 288 examples are perhaps
> somewhat more convincing though...
The disadvantage of doing it this way (or with a class wrapping the
generator) is that it is implicit. If I were reading the pickled_file
code, I would have no idea where the self.l comes from. If it is coming
from the 'for' loop, why not just be able to explicitly say that?
I agree that this is a confusing way to use generators. But it is the
expected way to use "code blocks" as found in other languages. It would
take some getting used to that 'for' can be used this way, but I think it
would be worth it.
-Brian
More information about the Python-Dev
mailing list