[Python-ideas] Possible PEP 380 tweak
Jacob Holm
jh at improva.dk
Wed Oct 27 09:57:16 CEST 2010
On 2010-10-26 19:01, Guido van Rossum wrote:
> On Tue, Oct 26, 2010 at 5:22 AM, Jacob Holm <jh at improva.dk> wrote:
> [...]
>>>> Here's a stupid idea... let g.close take an optional argument that it
>>>> can return if the generator is already exhausted and let it return the
>>>> value from the StopIteration otherwise.
>>>>
>>>> def close(self, default=None):
>>>> if self.gi_frame is None:
>>>> return default
>>>> try:
>>>> self.throw(GeneratorExit)
>>>> except StopIteration as e:
>>>> return e.args[0]
>>>> except GeneratorExit:
>>>> return None
>>>> else:
>>>> raise RuntimeError('generator ignored GeneratorExit')
>>>
>>> You'll have to explain why None isn't sufficient.
>
>> It is not really necessary, but seemed "cleaner" somehow. Think of
>> "g.close(default)" as "get me the result if possible, and this default
>> otherwise". Then think of dict.get()...
>
> Hm, I'd say there always is a result -- it just sometimes is None. I
> really don't want to make distinctions between falling off the end of
> the function, "return" without a value, "return None", "raise
> StopIteration()", "raise StopIteration(None)", or even (in response to
> a close() request) "raise GeneratorExit".
None of these cover the distinction I am making. I want to distinguish
between a non-exhausted and an exhausted generator.
When calling close on a non-exhausted generator, the generator decides
how to return by any one of the means you mentioned. In this case you
are right that there is always a result.
When calling close on an exhausted generator, the generator has no
choice in the matter as the "true" return value was thrown away. We
have to return *something*, but calling it the "result" of the generator
is stretching it too far. Making it possible to return something other
than None in this case seems to be analogous to dict.get().
If we chose to use a different method (e.g. Nicks "finish") for getting
the "result", I would instead raise a RuntimeError when calling it on an
exhausted generator. i.o.w, I would want it defined something like this:
def finish(self):
if self.gi_frame is None:
raise RuntimeError('generator already finished')
try:
self.throw(GeneratorExit)
except StopIteration as e:
return e.args[0]
except GeneratorExit:
return None # XXX debatable but unimportant to me
else:
raise RuntimeError('generator ignored GeneratorExit')
(possibly using a new GeneratorReturn exception instead)
You might argue for using a different exception for signaling the
exhausted case, e.g.:
class GeneratorFinishedError(StandardError):
"""finish() called on exhaused generator."""
but that only really makes sense if you think calling finish without
knowing whether the generator is exhausted is a reasonable thing to do.
*If* that is the case, we should also consider adding a 'default'
argument to finish which (if provided) could be returned instead of
raising the exception (kind of like dict.pop).
- Jacob
More information about the Python-ideas
mailing list