[Python-ideas] with *context_managers:

Alon Horev alon at horev.net
Tue Apr 3 10:02:25 CEST 2012


Another proposal, change nested to work with generators:
with nested(open(path) for path in files):
    ....

pros:
1. lazy evaluation of context manager creation (which is everything that is
bad with today's nested).
2. shorter than ContextStack.

cons:
1. generators are not always an option, in these cases ContextStack is the
way to go.
2. a little implicit - I can imagine a python newbie swearing my mom
because he didn't know he should use a generator instead of a list.

                          thanks, Alon Horev



On Mon, Apr 2, 2012 at 11:52 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:

> On Tue, Apr 3, 2012 at 1:34 AM, Sven Marnach <sven at marnach.net> wrote:
> > which only works for a fixed number of context managers.  And there is
> > a class 'ContextStack' in Nick Coghlan's 'contextlib2' library [1],
> > which might be included in Python 3.3.  With this class, you could
> > write your code as
> >
> >    with ContextStack() as stack:
> >        for cm in context_managers:
> >            stack.enter_context(cm)
> >
> > This still leaves the question whether your proposed syntax would be
> > preferable, also with regard to issue 2292 [2].
>
> Both "with *(iterable)" and "for cm in iterable: stack.enter(cm)" are
> flawed in exactly the same way that contextlib.nested() is flawed:
> they encourage creating the iterable of context managers first, which
> means that inner __init__ methods are not covered by outer __exit__
> methods.
>
> This breaks as soon as you have resources (such as files) where the
> acquire/release resource management pairing is actually
> __init__/__exit__ with __enter__ just returning self rather than
> acquiring the resource. If the iterable of context managers is created
> first, then the outer resources *will be leaked* if any of the inner
> constructors fail. The only way to write code that handles an
> arbitrary number of arbitrary context managers in a robust fashion is
> to ensure the initialisation steps are also covered by the outer
> context managers:
>
>    with CallbackStack() as stack:
>        for make_cm in cm_factories:
>            stack.enter(make_cm())
>
> (Note that I'm not particularly happy with the class and method names
> for contextlib2.ContextStack, and plan to redesign it a bit before
> adding it to the stdlib module:
>
> https://bitbucket.org/ncoghlan/contextlib2/issue/8/rename-contextstack-to-callbackstack-and
> )
>
> The only time you can get away with a contextlib.nested() style API
> where the iterable of context managers is created first is when you
> *know* that all of the context managers involved do their resource
> acquisition in __enter__ rather than __init__. In the general case,
> though, any such API is broken because it doesn't reliably clean up
> files and similar acquired-on-initialisation resources.
>
> Cheers,
> Nick.
>
> --
> Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> http://mail.python.org/mailman/listinfo/python-ideas
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20120403/8ac029d8/attachment.html>


More information about the Python-ideas mailing list