Операторы with
или менеджеры контекста предназначены для помощи с ресурсами (хотя их можно использовать и для гораздо большего).
Допустим, вы открыли файл на запись:
f = open(path, "w")
Теперь у вас есть дескриптор открытого файла. Во время обработки вашего файла никакая другая программа не может писать в него. Чтобы другие программы могли писать в него, вы должны закрыть дескриптор файла:
f.close()
Но перед закрытием файла произошла ошибка:
f = open(path, "w")
data = 3/0 # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
f.close()
Что произойдет сейчас, так это то, что функция или вся программа завершится, оставив ваш файл с открытым дескриптором. (CPython очищает дескрипторы при завершении, а дескрипторы освобождаются вместе с программой, но на это рассчитывать не стоит)
Оператор with гарантирует, что как только вы покинете его отступ, он закроет дескриптор файла:
with open(path, "w") as f:
data = 3/0 # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
# In here the file is already closed automatically, no matter what happened.
Операторы with
можно использовать для многих других целей. Например: threading.Lock()
lock = threading.Lock()
with lock: # Lock is acquired
do stuff...
# Lock is automatically released.
Почти все, что делается с помощью менеджера контекста, можно сделать с помощью try: ... finally: ...
, но менеджеры контекста приятнее в использовании, более удобны, более читабельны, а реализация __enter__
и __exit__
обеспечивает простой в использовании интерфейс.
Создание контекстных менеджеров осуществляется путем реализации __enter__()
и __exit__()
в обычном классе.
__enter__()
сообщает, что делать при запуске диспетчера контекста и __exit__()
, когда диспетчер контекста существует (предоставляя исключение методу __exit__()
, если возникло исключение)
Ярлык для создания контекстных менеджеров можно найти в contextlib. Он обертывает генератор как контекстный менеджер.
person
Bharel
schedule
12.04.2016