[Python-ideas] with statement: multiple context manager

26 views
Skip to first unread message

Christian Heimes

unread,
Mar 1, 2009, 8:49:03 AM3/1/09
to python...@python.org
Hello fellow Pythonistas!

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

Mathias Panzenböck

unread,
Mar 1, 2009, 9:30:38 AM3/1/09
to python...@python.org
Why not use this?

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

Guido van Rossum

unread,
Mar 1, 2009, 2:46:17 PM3/1/09
to Christian Heimes, python...@python.org

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/)

Eli Courtwright

unread,
Mar 1, 2009, 2:53:28 PM3/1/09
to python...@python.org
On Sun, Mar 1, 2009 at 2:46 PM, Guido van Rossum <gu...@python.org> wrote:
> 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.

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

Chris Rebert

unread,
Mar 1, 2009, 3:22:53 PM3/1/09
to Eli Courtwright, python...@python.org
On Sun, Mar 1, 2009 at 11:53 AM, Eli Courtwright <e...@courtwright.org> wrote:
> On Sun, Mar 1, 2009 at 2:46 PM, Guido van Rossum <gu...@python.org> wrote:
>> 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.
>
> 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.

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

Christian Heimes

unread,
Mar 1, 2009, 3:57:50 PM3/1/09
to python...@python.org
Chris Rebert wrote:
> While I still mostly like the idea, it does seem to undermine Python's
> uniformity a bit.

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

Gregory P. Smith

unread,
Mar 1, 2009, 4:01:47 PM3/1/09
to Guido van Rossum, python...@python.org, Christian Heimes
On Sun, Mar 1, 2009 at 11:46 AM, Guido van Rossum <gu...@python.org> wrote:
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())

Alternatively if closer conformity with for loop syntax is desirable consider this:

with lock, open(infile), open(outfile) as lock, fin, fout: 
    fout.fwrite(fin.read())

Calvin Spealman

unread,
Mar 1, 2009, 4:15:45 PM3/1/09
to Gregory P. Smith, Christian Heimes, python...@python.org
On Sun, Mar 1, 2009 at 4:01 PM, Gregory P. Smith <gr...@krypto.org> wrote:
> Alternatively if closer conformity with for loop syntax is desirable
> consider this:
> with lock, open(infile), open(outfile) as lock, fin, fout:
>     fout.fwrite(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

Chris Rebert

unread,
Mar 1, 2009, 4:35:07 PM3/1/09
to python...@python.org
On Sun, Mar 1, 2009 at 12:57 PM, Christian Heimes <li...@cheimes.de> wrote:
> Chris Rebert wrote:
>> While I still mostly like the idea, it does seem to undermine Python's
>> uniformity a bit.
>
> 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:
> ...

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

Terry Reedy

unread,
Mar 1, 2009, 4:45:07 PM3/1/09
to python...@python.org
Calvin Spealman wrote:
> On Sun, Mar 1, 2009 at 4:01 PM, Gregory P. Smith <gr...@krypto.org> wrote:
>> Alternatively if closer conformity with for loop syntax is desirable
>> consider this:
>> with lock, open(infile), open(outfile) as lock, fin, fout:
>> fout.fwrite(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.

I prefer this also, for the same reasons.

tjr

Guido van Rossum

unread,
Mar 1, 2009, 5:01:47 PM3/1/09
to ironf...@gmail.com, Christian Heimes, python...@python.org
On Sun, Mar 1, 2009 at 1:15 PM, Calvin Spealman <ironf...@gmail.com> wrote:
> On Sun, Mar 1, 2009 at 4:01 PM, Gregory P. Smith <gr...@krypto.org> wrote:
>> Alternatively if closer conformity with for loop syntax is desirable
>> consider this:
>> with lock, open(infile), open(outfile) as lock, fin, fout:
>>     fout.fwrite(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.

-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/)

Guido van Rossum

unread,
Mar 1, 2009, 5:14:30 PM3/1/09
to Chris Rebert, python...@python.org
On Sun, Mar 1, 2009 at 1:35 PM, Chris Rebert <pyi...@rebertia.com> wrote:
> On Sun, Mar 1, 2009 at 12:57 PM, Christian Heimes <li...@cheimes.de> wrote:
>> Chris Rebert wrote:
>>> While I still mostly like the idea, it does seem to undermine Python's
>>> uniformity a bit.
>>
>> 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:
>>      ...
>
> 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.

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/)

Chris Rebert

unread,
Mar 1, 2009, 5:22:56 PM3/1/09
to Guido van Rossum, python...@python.org

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

Georg Brandl

unread,
Mar 2, 2009, 3:10:41 AM3/2/09
to python...@python.org
Guido van Rossum schrieb:

> On Sun, Mar 1, 2009 at 1:15 PM, Calvin Spealman <ironf...@gmail.com> wrote:
>> On Sun, Mar 1, 2009 at 4:01 PM, Gregory P. Smith <gr...@krypto.org> wrote:
>>> Alternatively if closer conformity with for loop syntax is desirable
>>> consider this:
>>> with lock, open(infile), open(outfile) as lock, fin, fout:
>>> fout.fwrite(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.
>
> -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.

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

Sturla Molden

unread,
Mar 2, 2009, 7:21:09 AM3/2/09
to python...@python.org
On 3/1/2009 9:57 PM, Christian Heimes wrote:

> 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

Mathias Panzenböck

unread,
Mar 26, 2009, 11:07:25 AM3/26/09
to python...@python.org
Sturla Molden wrote:
> On 3/1/2009 9:57 PM, Christian Heimes wrote:
>
>> 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:
>
>

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

Guido van Rossum

unread,
Mar 26, 2009, 11:14:44 AM3/26/09
to Mathias Panzenböck, python...@python.org

No, we should maintain the parallel with" import a, b as c, d".

--
--Guido van Rossum (home page: http://www.python.org/~guido/)

Sturla Molden

unread,
Mar 26, 2009, 11:42:02 AM3/26/09
to Python-Ideas
On 3/26/2009 4:07 PM, Mathias Panzenböck wrote:

> 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

Guido van Rossum

unread,
Mar 26, 2009, 12:33:45 PM3/26/09
to Sturla Molden, Python-Ideas
On Thu, Mar 26, 2009 at 8:42 AM, Sturla Molden <stu...@molden.no> wrote:
> On 3/26/2009 4:07 PM, Mathias Panzenböck wrote:
>
>> 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?

No, the parens will be syntactically *illegal*.

--
--Guido van Rossum (home page: http://www.python.org/~guido/)

Terry Reedy

unread,
Mar 26, 2009, 6:15:44 PM3/26/09
to python...@python.org
Guido van Rossum wrote:


> No, we should maintain the parallel with" import a, b as c, d".

Which should then be mentioned in the doc.

Reply all
Reply to author
Forward
0 new messages