Kristján Valur Jónsson added the comment:

"locally visible" is, I think a very misleading term.  How is

with ignore_error, acquire_resource as r:
   doo_stuff_with_resource(r) #can be silently skipped

any more locally visible than
with acquire_resource_ignore_error as r:
    doo_stuff_with resource(r) # can be silently skipped.

? does the "nested with" syntax immediatelly tell you "hey, the body can be 
silently skipped"?

Requiring that some context manager patterns must be done with a special syntax 
is odd.  What is more, it prohibits us to abstract away context managers.  For 
instance, you can write a function like this

def execute_with_context(ctxt, fn, args):
    with ctxt:
        return fn(*args)

but if your context manager is of the kind mentioned, i.e. requiring the double 
syntax, you are screwed.

Basically, what I'm proposing (and what the patch provides) is that you can 
write this code:
@contextmanager
def nestedc(ca, cb):
    with ca as a, cb as b:
        yield a, b

and have it work for _all_ pair of ca, cb.  This then, allows context managers 
to be used like abstract entities, like other objects in the language.  It is 
_not_ about flow control, but about completeness.

A similar pattern for functions is already possible:
def nestedf(fa, fb):
    def helper(v):
        return fa(fb(v))
    return helper

And so, we could write:
execute_with_context(nestedc(ca, cb), nestedf(fa, fb), ('foo',))

Current python does not allow this for arbitrary pairs ca, cb.  My version 
does.  This is what I'm advocating.  That programmers are given the tool to 
combine context managers if they want.
 

As for "contextlib.nested()".
I'm not necessarily advocation its resuciation in the standardlib, but adding 
that to the patch here to demonstrate how it now _works_.

Here is a simpler version of contextlib.nested:

@contextmanager
def nested_empty():
    yield []

@contextmanager
def nested_append(prev, next):
    with prev as a, next as b:
        a.append(b)
        yield a

def nested(*managers):
    total = nested_empty()
    for mgr in managers:
        total = nested_append(total, mgr)
    return total

Pretty nice, no?

Now we come to the argument with nested(open(a), open(b)).
I see your point, but I think that the problem is not due to nested, but to 
open.  Deprecating nested, even as a programming pattern demonstration is 
throwing out the baby with the bathwater.

I´ve coined the term "hybrid context manager" (at least I think I have)to mean 
resources that are their own context managers.  They're hybrid because they are 
acquired explicitly, but can be released via a context manager.  The context 
manager is a bolt on, an afterthought.  Instead of adding __exit__() to files, 
and allowing
with open(fn) as f: pass
We should have encouraged the use of proper context managers:
with opened(fn) as f: pass
or 
with closing(f):  pass

Now, we unfortunately have files being context managers and widely see the 
pattern
with open(fn) as f, open(fn2) as f2:
    pass

But how is this bug here:
with nested(open(fn), open(fn2)) as f, f2: pass

any more devuiys than
f, f2 = open(fn), open(fn2)
with f, f2: pass
?

The problem is that files aren't "real" context managers but "hybrids" and this 
is what we should warn people about.  The fact that we do have those hybrids in 
our code base should not be cause to remove tools that are designed to work 
with "proper" context managers.

The decision to remove "nested" on these grounds sets the precedence that we 
cannot have any functions that operate on context managers.  In fact, what this 
is really is saying is this:

"context managers should only be used with the "with" statement and only 
instantiated in-line.
Anything else may introduce sublte bugs because some context managers are in 
fact not context managers, but the resource that they manage.
"

In my opinion, it would have been better to deprecate the use of files as 
context managers, and instead urge people to use proper context managers for 
the:  (the proposed) contextlib.opened and (the existing) contextlib.closing)

K

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue18677>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to