On a regularly basis I'm bothered and annoyed by the fact that the with
statement takes only one context manager. Often I need to open two files
to read from one and write to the other. I propose to modify the with
statement to accept multiple context manangers.
Example
=======
The nested block::
with lock:
with open(infile) as fin:
with open(outfile, 'w') as fout:
fout.write(fin.read())
could be written as::
with lock, open(infile) as fin, open(outfile, 'w') as fout:
fout.write(fin.read())
The context managers' __enter__() and __exit__() methods are called FILO
(first in, last out). When an exception is raised by the __enter__()
method, the right handed context managers are omitted.
Grammar
=======
I'm not sure if I got the grammar right but I *think* the new grammar
should look like::
with_stmt: 'with' with_vars ':' suite
with_var: test ['as' expr]
with_vars: with_var (',' with_var)* [',']
Christian
_______________________________________________
Python-ideas mailing list
Python...@python.org
http://mail.python.org/mailman/listinfo/python-ideas
from contextlib import nested
with nested(lock, open(infile), open(outfile, 'w')) as (_, fin, fout):
fout.write(fin.read())
Ok, the _ is ugly, but is it ugly enough so we need this extension to the with
statement?
-panzi
I am sympathetic to this desire -- I think we almost added this to the
original PEP but decided to hold off until a clear need was found.
--
--Guido van Rossum (home page: http://www.python.org/~guido/)
I second the motion to have this syntax added to the language. I've
often had to write nested with blocks to open one file for reading and
another for writing.
- Eli
It does seem slightly incongruous though, given that the
for-statement, which is quite similar to the with-statement in that
they both bind new variables in a subsidiary block of code, does not
directly support multiple simultaneous bindings.
To put it more concretely, currently one must write:
for a, b, c in zip(seq1, seq2, seq3):
#body
Rather than:
for a in seq1, b in seq2, c in seq3:
#body
But for some reason we're proposing to, in a way, make nested() built
into `with` but not make zip() likewise built into `for`.
While I still mostly like the idea, it does seem to undermine Python's
uniformity a bit.
Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com
I played with both possible versions before I wrote the proposal. Both
ways have their pros and cons. I'm preferring the proposed way::
with a, b as x, d as y:
...
over the other possibility::
with a, b, c as _, x, y:
...
for two reasons. For one I dislike the temporary variable that is
required for some cases, e.g. the case I used in my initial proposal. It
doesn't feel quite right to use a useless placeholder. The proposed way
follows the example of the import statement, too::
from module import a, b as x, d as y
Christian
On Sun, Mar 1, 2009 at 5:49 AM, Christian Heimes <li...@cheimes.de> wrote:
> On a regularly basis I'm bothered and annoyed by the fact that the with
> statement takes only one context manager. Often I need to open two files
> to read from one and write to the other. I propose to modify the with
> statement to accept multiple context manangers.
>
> Example
> =======
>
> The nested block::
>
> with lock:
> with open(infile) as fin:
> with open(outfile, 'w') as fout:
> fout.write(fin.read())
>
>
> could be written as::
>
> with lock, open(infile) as fin, open(outfile, 'w') as fout:
> fout.write(fin.read())
+1
We don't have multi-assignment statements in favor of the unpacking
concept, and I think it carries over here. Also, as mentioned, this
goes along with the lack of any multi-for statement. The `x as y` part
of the with statement is basically an assignment with extras, and the
original suggestion then combines multiple assignments on one line.
This option, I think, is more concise and readable.
--
Read my blog! I depend on your acceptance of my opinion! I am interesting!
http://techblog.ironfroggy.com/
Follow me if you're into that sort of thing: http://www.twitter.com/ironfroggy
You misunderstand me. My quibble isn't over the exact syntax (in fact,
I completely agree about the superiority of the proposed ordering),
but rather that we're introducing syntax to do something that can
already be done with a function (nested()) and is /extremely/ similar
to another case (parallel for-loop) where we are opting to still
require the use of a function (zip()). This proposed asymmetry
concerns me.
> The proposed way
> follows the example of the import statement, too::
>
> from module import a, b as x, d as y
This parallel does quell my concern somewhat.
Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com
I prefer this also, for the same reasons.
tjr
-1 for this variant. The syntactic model is import: import foo as bar,
bletch, quuz as frobl. If we're doing this it should be like this.
--
--Guido van Rossum (home page: http://www.python.org/~guido/)
Hm. While we can indeed write the equivalent of the proposed "with a,
b:" today as "with nested(a, b):", I don't think that the situation is
quite comparable to a for-loop over a zip() call. The nested() context
manager isn't particularly intuitive to me (and Nick just found a
problem in a corner case of its semantics). Compared to nested(), I
find "with a, b:" very obvious as a shorthand for nested
with-statements:
with a:
with b:
...
--
--Guido van Rossum (home page: http://www.python.org/~guido/)
Ok, fine by me. Just wanted to ensure the point was brought up and
adaquately responded to.
On another note, someone ought to draft a revision to PEP 343 to
document this proposal.
Cheers,
Chris
--
Follow the path of the Iguana...
http://rebertia.com
Also, the "a as b, c as d" syntax better conveys the fact that the managers
are called sequentially, and not somehow "in parallel".
Georg
> with a, b as x, d as y:
I'd like to add that parentheses improve readability here:
with a, (b as x), (d as y):
I am worried the proposed syntax could be a source of confusion and
errors. E.g. when looking at
with a,b as c,d:
my eyes read
with nested(a,b) as c,d:
when Python would read
with a,(b as c),d:
It may actually be better to keep the current implementation with
contextlib.nested.
If contextlib.nested is not well known (I only learned of its existence
recently), maybe it should be better documented? Tutorial examples of
the with statement should cover contextlib.nested as well.
Sturla Molden
Good point. Maybe that would be better:
with a,b as c,d:
reads as:
with nested(a,b) as c,d:
This means there can only be one "as" in a with statement with the further
implication that even unneeded values have to be assigned:
with a,b,c as x,unused,y:
Not as nice, but much more unambiguous. Unambiguity is what we need, I think.
You can always assing to _, wich is very commonly used for unneeded values
(well, or for the l10n hook - so using that name would not be very unambiguous).
-panzi
No, we should maintain the parallel with" import a, b as c, d".
--
--Guido van Rossum (home page: http://www.python.org/~guido/)
> Good point. Maybe that would be better:
>
> with a,b as c,d:
No. See Guido's reply.
I was just trying to say that
with nested(a,b) as c,d:
is more readble than
with a as c, b as d:
which would argue against new syntax and better documentation of
contextlib.nested. However, as the tuple (a,b) is built prior to the
call to nested, new syntax is needed.
It still does not hurt to put in parentheses for readability here:
with (a as c), (b as d):
Perhaps parentheses should be recommended in the documentation, even
though they are syntactically superfluous here?
Sturla Molden
No, the parens will be syntactically *illegal*.
--
--Guido van Rossum (home page: http://www.python.org/~guido/)
> No, we should maintain the parallel with" import a, b as c, d".
Which should then be mentioned in the doc.