[Python-ideas] Deterministic iterator cleanup

Nathaniel Smith njs at pobox.com
Fri Oct 21 23:45:43 EDT 2016


On Fri, Oct 21, 2016 at 3:48 PM, Amit Green <amit.mixie at gmail.com> wrote:
> NOTE: This is my first post to this mailing list, I'm not really sure
>       how to post a message, so I'm attempting a reply-all.
>
> I like Nathaniel's idea for __iterclose__.
>
> I suggest the following changes to deal with a few of the complex issues
> he discussed.
>
> 1.  Missing __iterclose__, or a value of none, works as before,
>     no changes.
>
> 2.  An iterator can be used in one of three ways:
>
>     A. 'for' loop, which will call __iterclose__ when it exits
>
>     B.  User controlled, in which case the user is responsible to use the
>         iterator inside a with statement.
>
>     C.  Old style.  The user is responsible for calling __iterclose__
>
> 3.  An iterator keeps track of __iter__ calls, this allows it to know
>     when to cleanup.
>
>
> The two key additions, above, are:
>
>     #2B. User can use iterator with __enter__ & __exit cleanly.
>
>     #3.  By tracking __iter__ calls, it makes complex user cases easier
>          to handle.

These are interesting ideas! A few general comments:

- I don't think we want the "don't bother to call __iterclose__ on
exhaustion" functionality --it's actually useful to be able to
distinguish between

    # closes file_handle
    for line in file_handle:
        ...

and

    # leaves file_handle open
    for line in preserve(file_handle):
        ...

To be able to distinguish these cases, it's important that the 'for'
loop always call __iterclose__ (which preserve() might then cancel
out).

- I think it'd be practically difficult and maybe too much magic to
add __enter__/__exit__/nesting-depth counts to every iterator
implementation. But, the idea of using a context manager for repeated
partial iteration is a great idea :-). How's this for a simplified
version that still covers the main use cases?

@contextmanager
def reuse_then_close(it):   # TODO: come up with a better name
    it = iter(it)
    try:
        yield preserve(it)
    finally:
        iterclose(it)

with itertools.reuse_then_close(some_generator(...)) as it:
    for obj in it:
        ...
    # still open here, because our reference to the iterator is
wrapped in preserve(...)
    for obj in it:
        ...
# but then closed here, by the 'with' block

-n

-- 
Nathaniel J. Smith -- https://vorpus.org


More information about the Python-ideas mailing list