Python nested context manager on multiple lines
Solution 1
Backslash characters
Two or more physical lines may be joined into logical lines using backslash characters (
\
)
(citing the Explicit line joining section)
If you want put context managers on different lines, you can make that work by ending lines with backslashes:
with context1 as a,\
context2 as b:
pass
contextlib.ExitStack
contextlib.ExitStack
is a
context manager that is designed to make it easy to programmatically combine other context managers and cleanup functions, especially those that are optional or otherwise driven by input data.
It's available in Python 3.3 and newer, and allows to enter a variable number of context managers easily. For just two context managers the usage looks like this:
from contextlib import ExitStack
with ExitStack() as es:
a = es.enter_context(context1)
b = es.enter_context(context2)
Nesting
It's possible to split a context expression across several nested with
statements:
With more than one item, the context managers are processed as if multiple with statements were nested:
with A() as a, B() as b:
suite is equivalent to
with A() as a: with B() as b: suite
(from The with statement)
Solution 2
There is a way to creatively use the parentheses and avoid the backslash: parenthesize the expression before as
. Not very sightly, though:
with (
open('/etc/passwd')) as foo, (
open('/tmp/bar')) as bar:
pass # this parses correctly
It's easy to nest more and more if needed.
Solution 3
with context1 as a, \
context2 as b:
pass
Like any line-break, backslash provides the solution
Solution 4
Your example is equivalent to:
with context1 as a:
with context2 as b:
pass
which looks nice on two lines.
Reference: https://docs.python.org/2.7/reference/compound_stmts.html#the-with-statement
Simon Boudrias
Originally from Montréal, but explored the world through different long term work opportunities: San Francisco 🚆Beijing 🚆Vancouver. Main contributor on Yeoman project and original author of Inquirer. I also manage open sourced many other semi-popular projects. Checkout https://github.com/SBoudrias to find out more.
Updated on June 15, 2022Comments
-
Simon Boudrias almost 2 years
In Python 2.6, we used to format our nested context manager that way:
with nested( context1, context2 ) as a, b: pass
From Python 2.7 and on,
nested
is deprecated. I've seen lots of example of multiple context manager on a single line, but I can't find a syntax that allow them on multiple lines. How would you do this?# That's working fine with context1 as a, context2 as b: pass # But how do we make it multine? # These are not working with ( context1, context2 ) as a, b: pass with context1 as a, context2 as b: pass
-
Simon Boudrias almost 9 yearsIs this the only syntax - because it's very ugly... :(
-
Joseph Garvin over 7 yearsCan't believe I'm saying it but in this instance python syntax is terrible compared to lisp. Multiple assignments in a (let) or other binding form looks completely natural... but this is awkward.
-
tebanep almost 7 yearsThis is the prettiest solution. Thanks!
-
isarandi almost 7 yearsWhy would you want to avoid backslashes in this case though? The open parens play essentially the same role here, but it also becomes more cryptic.
-
9000 almost 7 years@isarandi: A backslash as line continuation is easier to break when editing than some other things. PEP-8 recommends the use of parens in favor of backslash continuation. BTW the same PEP-8 suggests to use a
\
exactly with multiplewith
statements. I personally prefer nesting ofwith
, but added this answer for completeness. -
CMCDragonkai about 4 yearsWhat if
B()
requiresa
? Is there a way to pass it in?