Вложенный менеджер контекста Python на нескольких строках

В Python 2.6 мы форматировали наш вложенный менеджер контекста таким образом:

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

Из Python 2.7 и on, nested устарел. Я видел много примеров из нескольких менеджеров контекста в одной строке, но я не могу найти синтаксис, который позволяет их на нескольких строках. Как вы это сделаете?

# That 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

Ответ 1

Символы с обратной косой чертой

Две или несколько физических линий могут быть объединены в логические линии, используя символы обратной косой черты (\)

(ссылаясь на раздел Явная строка, соединяющая)

Если вы хотите поставить менеджеров контекста на разные строки, вы можете сделать эту работу, завершая строки обратными косыми чертами:

with context1 as a,\
     context2 as b:
    pass

contextlib.ExitStack

contextlib.ExitStack является

менеджер контекста, который предназначен для упрощения программно объединить других менеджеров контекста и функций очистки, особенно тех, которые которые являются необязательными или иным образом управляются входными данными.

Он доступен в Python 3.3 и новее и позволяет легко вводить переменное количество менеджеров контекста. Для двух менеджеров контекста использование выглядит следующим образом:

from contextlib import ExitStack

with ExitStack() as es:
    a = es.enter_context(context1)
    b = es.enter_context(context2)

Вложение

Можно разбить контекстное выражение на несколько вложенных операторов with:

С более чем одним элементом менеджеры контекста обрабатываются так, как будто множественные с операторами были вложены:

with A() as a, B() as b:

набор эквивалентен

with A() as a:
    with B() as b:
        suite

(из Инструкция with)

Ответ 2

Существует способ творчески использовать круглые скобки и избегать обратной косой черты: заключить в скобки выражение перед as. Не очень зрелищно, хотя:

with (
  open('/etc/passwd')) as foo, (
  open('/tmp/bar')) as bar:
  pass  # this parses correctly

Легко вложить все больше и больше при необходимости.

Ответ 4

with context1 as a, \
context2 as b:
pass

Как и любой разрыв строки, обратная косая черта обеспечивает решение