Оператор with

Оновлено: 24.04.2023

Оператор with використовується для обгортання виконання блоку методами, визначеними контекстним менеджером (див. розділ З менеджерами контексту операторів). Це дозволяє інкапсулювати загальні try…except…finally моделі використання для зручного повторного використання.

with_stmt          ::=  "with" ( "(" with_stmt_contents ","? ")" | with_stmt_contents ) ":" suite
with_stmt_contents ::=  with_item ("," with_item)*
with_item          ::=  expression ["as" target]

Виконання оператора with з одним «елементом» відбувається наступним чином:

Контекстний вираз (вираз, поданий у with_item) обчислюється для отримання контекстного менеджера. Менеджер контексту __enter__() завантажується для подальшого використання. Менеджер контексту __exit__() завантажується для подальшого використання. Викликається метод __enter__() контекстного менеджера. Якщо мета була включена в оператор with, їй призначається значення, що повертається з __enter__(). Примітка The with statement guarantees that if the __enter__() method returns without an error, then __exit__() will always be called. Thus, if an error occurs during the assignment to the target list, it will be treated the same as an error occurring within the suite would be. See step 7 below. Сюїта виконана. Викликається метод __exit__() контекстного менеджера. Якщо виняткова ситуація призвела до виходу з набору, його тип, значення та відстеження передаються як аргументи __exit__(). В іншому випадку надається три аргументи None. Якщо набір було закрито через виняток, а значення, яке повертає метод __exit__(), було false, виняток створюється повторно. Якщо повернене значення було істинним, виняток пригнічується, і виконання продовжується з оператором, наступним за оператором with. Якщо вихід із набору було завершено з будь-якої причини, крім винятку, значення, що повертається з __exit__(), ігнорується, і виконання продовжується у звичайному місці для того виду виходу, який було зроблено.

Наступний код:

with EXPRESSION as TARGET:
    SUITE

семантично еквівалентний:

manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False

try:
    TARGET = value
    SUITE
except:
    hit_except = True
    if not exit(manager, *sys.exc_info()):
        raise
finally:
    if not hit_except:
        exit(manager, None, None, None)

З більш ніж одним елементом менеджери контексту обробляються так, ніби кілька операторів with були вкладеними:

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

семантично еквівалентний:

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

Ви також можете писати багатоелементні контекстні менеджери в кілька рядків, якщо елементи оточені дужками. Наприклад:

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