Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python nested context manager on multiple lines [duplicate]

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
like image 512
Simon Boudrias Avatar asked Jul 22 '15 18:07

Simon Boudrias


3 Answers

Python 3.10 and newer

Starting from Python 3.10, parentheses are allowed, and you can finally do this:

with (
    context1 as a,
    context2 as b
):
    pass

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)

like image 85
vaultah Avatar answered Oct 21 '22 19:10

vaultah


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.

like image 14
9000 Avatar answered Oct 21 '22 20:10

9000


with context1 as a, \
context2 as b:
pass

Like any line-break, backslash provides the solution

like image 2
Sudeep Juvekar Avatar answered Oct 21 '22 18:10

Sudeep Juvekar