[Python-ideas] generator.close

Jacob Holm jh at improva.dk
Wed Apr 11 12:50:28 CEST 2012


Hello Matt

On 04/11/2012 11:38 AM, Matt Joiner wrote:
> Why can't generator.close() return the value if a StopIteration is raised?
>
> The PEPs mentioned that it was proposed before, but I can't find any
> definitive reason, and it's terribly convenient if it does.
>

What should be returned when you call close on an already-exhausted 
generator?

You can't return the value of the final StopIteration unless you arrange 
to have that value stored somewhere.  Storing the value was deemed 
undesireable by the powers that be.

The alternative is to return None if the generator is already exhausted. 
  That would work, but severely reduces the usefulness of the change.

If you don't care about the performance of yield-from, it is quite easy 
to write a class you can use to wrap your generator-iterators and get 
the desired result (see untested example below).


- Jacob


import functools

class generator_result_wrapper(object):
     __slots__ = ('_it', '_result')

     def __init__(self, it):
         self._it = it

     def __iter__(self):
         return self

     def next(self):
         try:
             return self._it.next()
         except StopIteration as e:
             self._result = e.result
             raise

     def send(self, value):
         try:
             return self._it.send(value)
         except StopIteration as e:
             self._result = e.result
             raise

     def throw(self, *args, **kwargs):
         try:
             return self._it.throw(*args, **kwargs)
         except StopIteration as e:
             self._result = e.result
             raise

     def close(self):
         try:
             return self._result
         except AttributeError:
             pass
         try:
             self._it.throw(GeneratorExit)
         except StopIteration as e:
             self._result = e.result
             return self._result
         except GeneratorExit:
             pass

def close_result(func):
     @functools.wraps(func)
     def factory(*args, **kwargs):
         return generator_result_wrapper(func(*args, **kwargs))
     return factory




More information about the Python-ideas mailing list