New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
can't run close through itertools.chain on inner generator #48092
Comments
There is no way to get generators to clean up (run their 'finally' >>> def gen(n):
... try:
... # do stuff yielding values
... finally:
... # clean up
>>> c = chain.from_iterable(map(gen, (1,2,3)))
>>> next(c)
0
>>> # done with c, but can't clean up inner gen! Could you add a 'close' method to itertools.chain that would call close >>> with closing(chain.from_iterable(map(gen, (1,2,3)))) as c:
... next(c)
>>> # generator finalized by "with closing"! |
You somehow must tell the iterator that you are done with it. def wrapiterator(it):
for x in it:
yield x Then your sample becomes:
>>> with closing(wrapiterator(chain.from_iterable(
... map(gen, (1,2,3))))) as c:
... next(c) Which of course can be rewritten as: def closingiterator(it):
def wrapper():
for x in it:
yield x
return closing(wrapper()) >>> with closingiterator(chain.from_iterable(map(gen, (1,2,3))))) as c:
... next(c) This works because the only reference to the map() iterator is held by Your proposal implies that all c-based iterators need to grow a "close" |
What you propose is not portable code. It won't work on jython or Also I'm not asking that all c-based iterators grow a 'close' method For all other c-based iterators, you can do: with closing(gen()) as argument:
for x in map(fn, argument): ... which is portable. So I am only asking that 'close' be added to itertools.chain because -bruce Amaury Forgeot d'Arc wrote:
> Amaury Forgeot d'Arc <amauryfa@gmail.com> added the comment:
>
> You somehow must tell the iterator that you are done with it.
> This is best done by a "del c" in your first snippet, since c is the
> last reference to the iterator.
> To do this in a function (or a context manager), the trick is to wrap
> the map() iterator inside a generator function.
>
> def wrapiterator(it):
> for x in it:
> yield x
>
> Then your sample becomes:
>
>>>> with closing(wrapiterator(chain.from_iterable(
>>>>
> ... map(gen, (1,2,3))))) as c:
> ... next(c)
>
>
> Which of course can be rewritten as:
>
> def closingiterator(it):
> def wrapper():
> for x in it:
> yield x
> return closing(wrapper())
>
>
>>>> with closingiterator(chain.from_iterable(map(gen, (1,2,3))))) as c:
>>>>
> ... next(c)
>
>
> This works because the only reference to the map() iterator is held by
> the wrapper generator function. Calling its close() method will
> terminate the function, delete its locals, ultimately call the
> deallocator of the gen() iterator, which will fire the "finally" block.
>
> Your proposal implies that all c-based iterators need to grow a "close"
> method. This is not practical, and is best simulated with this wrapper
> generator: close()ing the wrapper will (recursively) destroy the iterators.
> If this also works for you, I suggest to close this issue.
> |
Sorry, am going to reject this. The use cases are somewhat uncommon |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: