The Python Programming Guide

Контекстный менеджер with

Блок with, часто называемый контекстным менеджером, позволяет некоторые вещи сделать более простыми, надёжными и даже более читаемыми. К примеру, часто используется при файловых операциях. Рассмотрим три варианта одной и той же операции:

#   1 - без использования with и обработки ошибок
outfile = open("test.txt", "w")
outfile.write("Lorum ipsum")
outfile.close()

#   2 - без использования with, но c обработкой ошибок
outfile = open("test.txt", "w")
try:
    outfile.write("Lorum ipsum")
finally:
    # не важно какая ошибка, главное закрыть файловый поток
    outfile.close()

#   3 - с использованием with
with open("test.txt", "w") as outfile:
    outfile.write("Lorum ipsum")

Первое, что должно броситься в глаза, это отсутствие вызываемого метода close() для закрытия файлового дескриптора в третьем варианте с использованием with. После выхода из этого контекстного менеджера наш файл test.txt будет закрыт автоматически.

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

Поддержка блока with в пользовательских объектах

Для поддержки работы блока with в пользовательских объектах необходимо реализовать два специальных метода __enter__() и __exit__():

Рассмотрим пример, где создадим простой объект для записи в файл по аналогии выше:

class FileWriter:
    def __init__(self, filename):
        self.filename = filename
    def __enter__(self):
        self.outfile = open(self.filename, "w")
        return self.outfile
    def __exit__(self):
        self.file.close()

with FileWriter("test.txt") as outfile:
    outfile.write("Hola!")