[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):

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

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