On Sun, Feb 3, 2013 at 1:47 AM, Yuval Greenfield email@example.com wrote:
I really like Golang's solution (defer) which Nick sort of emulates with ExitStack.
If ExitStack ever became a language feature
Why would it ever become a language feature? It works just fine as a context manager, and the need for it isn't frequent enough to justify special syntax.
we could write stuff like:
def f(): fhand = local open(path) process(fhand) ghand = local open(path2) process(ghand)
Why would you leave fhand open longer than necessary? The above would be better written as:
def f(): with open(path) as fhand: process(fhand) with open(path2) as ghand: process(ghand)
If you need both files open at the same time, you can use a nested context manager:
def f(): with open(path) as fhand: with open(path2) as ghand: process(fhand, ghand)
Or the nesting behaviour built into with statements themselves:
def f(): with open(path) as fhand, open(path2) as ghand: process(fhand, ghand)
It's only when the number of paths you need to open is dynamic that ExitStack comes into play (this is actually very close to the example in ExitStack's docstring, as handling a variable number of simultaneously open files was the use case that highlighted the fatal flaw in the way the old contextlib.nested design handled context managers that acquired the resource in __init__ rather than __enter__):
def f(*paths): with contextlib.ExitStack() as stack: files = [stack.enter_context(open(path)) for path in paths] process(files)
Function and class definitions control name scope (amongst other things), with statements control deterministic cleanup, loops control iteration. That's what I mean by "separation of concerns" in relation to these aspects of the language design and it's a *good* thing (and one of the key reasons with statements behave like PEP 343, rather than being closer to Guido's original looping idea that is described in PEP 340).