Контекстный менеджер 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__()
:
__enter__()
- в данном методе осуществляется обычно инициализация объекта и его возврат с помощьюreturn
.__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!")