Конструкция with - as: менеджер контекста

Конструкция with - as используется для оборачивания выполнения блока инструкций менеджером контекста. Часто это более удобная конструкция, чем изученная ранее try-except-finally.

Синтаксис конструкции with ... as:

"with" expression ["as" target] ("," expression ["as" target])* ":"
    suite

Если в конструкции with - as было несколько выражений, то это эквивалентно нескольким вложенным конструкциям:

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

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

with A() as a:
    with B() as b:
        suite
После слова as идёт переменная, куда записывается результат выражения, в нашем случае, получившийся после открытия файловый объект.

Для чего применяется конструкция with ... as?

Конструкция with - as применяется для получения гарантии того, что критические функции выполнятся в любом случае.

Самый распространённый пример использования этой конструкции - редактирование файлов. В прошлой лекции мы изучали работу с файлами с помощью open, .close, однако конструкция with ... as, как правило, является более удобной и гарантирует закрытие файла в любом случае.

with open('pyplanet.txt', 'w', encoding='utf-8') as f:
    print(f'1 / 0 = {1 / 0}', file=f)

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

f = open('pyplanet.txt', 'w', encoding='utf-8')
try:
    print(f'1 / 0 = {1 / 0}', file=f)
finally:
    f.close()

Что происходит при выполнении конструкции with - as:

  1. Выполняется выражение в конструкции with - as
  2. Загружается специальный метод __exit__ для дальнейшего использования
  3. Выполняется метод __enter__ Если конструкция with включает в себя слово as, то возвращаемое методом __enter__ значение записывается в переменную
  4. Выполняется suite.
  5. Вызывается метод __exit__, причём неважно, выполнилось ли suite или произошло исключение В этот метод передаются параметры исключения, если оно произошло, или во всех аргументах значение None, если исключения не было

Что за специальные методы? Это методы, которые могут определять и переопределять объекты, как встроенные в Python, так и написанные программистом.

У файла, очевидно, __exit__ - это вызов .close().

Так что впоследствии можно будет писать объекты, которые тоже можно оборачивать в with - as; обычно это те, которые требуют освобождения внешних ресурсов.