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

В Python 2.6 мы использовали такой формат для нашего вложенного диспетчера контекста:

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

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

# 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

person Simon Boudrias    schedule 22.07.2015    source источник
comment
Не уверен, почему это было помечено как повторяющееся. Другой пост не отвечает на вопрос. Я согласен с тем, что Python должен предлагать синтаксис, основанный на скобках, как для оператора if.   -  person Conchylicultor    schedule 02.02.2017


Ответы (4)


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

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

(со ссылкой на явное объединение строк раздел)

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

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 были вложены:

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

люкс эквивалентен

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

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

person vaultah    schedule 22.07.2015
comment
Это единственный синтаксис - потому что он очень уродливый ... :( - person Simon Boudrias; 22.07.2015
comment
Не могу поверить, что говорю это, но в данном случае синтаксис Python ужасен по сравнению с lisp. Множественные присвоения в (let) или другой форме связывания выглядят совершенно естественно ... но это неудобно. - person Joseph Garvin; 07.11.2016
comment
Что, если B() требует a? Есть ли способ передать это? - person CMCDragonkai; 28.04.2020

Есть способ творчески использовать круглые скобки и избегать обратной косой черты: заключить выражение в скобки перед as. Хотя не очень красиво:

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

При необходимости легко вкладывать все больше и больше.

person 9000    schedule 22.07.2015
comment
Это самое красивое решение. Спасибо! - person tebanep; 18.05.2017
comment
Но почему в этом случае нужно избегать обратной косой черты? Открытые паренсы играют здесь, по сути, ту же роль, но они также становятся более загадочными. - person isarandi; 22.06.2017
comment
@isarandi: обратную косую черту как продолжение строки легче прервать при редактировании, чем некоторые другие вещи. PEP-8 рекомендует использовать скобки в пользу продолжения обратной косой черты. Кстати, тот же PEP-8 предлагает использовать \ точно с несколькими операторами with. Я лично предпочитаю вложение with, но добавил этот ответ для полноты. - person 9000; 22.06.2017

with context1 as a, \
context2 as b:
pass

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

person Sudeep Juvekar    schedule 22.07.2015

Ваш пример эквивалентен:

with context1 as a:
    with context2 as b:
        pass

что красиво смотрится на двух строчках.

Ссылка: https://docs.python.org/2.7/reference/compound_stmts.html#the-with-statement

person Robᵩ    schedule 22.07.2015