[Python-ideas] should there be a difference between generators anditerators?

Bruce Frederiksen dangyogi at gmail.com
Thu Sep 4 18:30:25 CEST 2008


Raymond Hettinger wrote:
> From: "Bruce Frederiksen" <dangyogi at gmail.com>
>> 1.  All of the itertools and map (and I've no doubt left some others 
>> out here) be extended to propagate the extra generators methods: 
>> close, throw and send.
>
> Try wrapping each input iterator with an autocloser:
>
> def closer(it):
>    for elem in it:
>        yield elem
>    if hasattr(it, 'close'):
>        it.close()
>
> map(somefunc, closer(someiterable))
I don't think that this adds anything.  If the 'it' iterable is run to 
completion (and, presumably, does what 'close' will do anyway), this 
adds nothing.  And if the 'it' iterable is not run to completion, then 
neither is closer, and so it still adds nothing.  (And placing the 'if 
hasattr' clause under a 'finally' doesn't help, because the 'finally' is 
only run if the generator runs to completion or 'close' is called, and 
nobody is ever going to call close here on closer).  What I'm looking 
for is making the following work:

with contextlib.closing(map(somefunc, someiterable)) as it:
    for i in it:
        if somecondition: break
# at this point someiterable.close should have been run

Intuitively, I would think that the above should work, but it doesn't.  
Intuitively, I would think that if  Python defines 'close' and 'throw' 
methods to allow generators to properly clean up after themselves, that 
itertools and the 'for' statement would both honor these so that the 
'with' statement isn't even required here.  I can see arguments for not 
calling 'close' automatically in 'for' statements (though none for not 
calling 'throw' automatically); but I don't see any arguments against 
itertools honoring these methods.  If any of the itertools is passing 
values back from a generator (rather than a simple iterator), it would 
be very nice to retain the full semantics of the generator.

Now, for map, you could suggest that Python programmers understand these 
subtleties and write instead:

with contextlib.closing(someiterable) as it:
    for i in map(somefunc, it):

and this works for map.  But what about chain?

with contextlib.closing(chain.from_iterable(map(somegenerator, 
someiterable))) as it:
    for i in it:

This is my specific situation, and I need 'close' to be called on the 
currently active somegenerator within chain before the line following 
'with' is executed.  In my particular case, I don't think I need close 
on someiterable, but it seems to make sense to do this too.

Currently, I'm not using the 'with' clause and am relying on CPython's 
garbage collector to immediately call __del__ (which is defined to call 
close) when the 'for' statement abandons chain.  But this doesn't work 
in jython or ironpython...

-bruce

And, BTW, thank you for adding from_iterable to chain!



More information about the Python-ideas mailing list