Короткий ответ
Без with ресурс может не быть закрыт при возникновении исключения до явного вызова close(), что ведёт к утечке файловых дескрипторов или соединений, особенно заметной при длительной работе приложения под нагрузкой.
Как это работает подробнее
Без with закрытие ресурса обычно пишут вручную после кода его использования; если между открытием и close() происходит исключение, строка close() может не выполниться, и ресурс останется открытым до завершения процесса или сборки мусора (что не гарантировано по времени).
Пример кода
example-253.py
# Пример с утечкой при исключении (намеренная ошибка для анализа):
def read_bad(path):
f = open(path)
data = f.read()
risky_operation(data) # если здесь исключение, f.close() ниже не выполнится
f.close()
return data
# Диагностика: lsof -p <pid> или мониторинг числа открытых дескрипторов процесса
# покажет рост со временем при повторных вызовах read_bad с ошибками внутри risky_operationЧто использовать на практике
- Практика. В долгоживущих backend-процессах такие утечки накапливаются — у ОС ограничено число открытых дескрипторов/соединений, и при их исчерпании новые
open()/connect()начинают падать с ошибками типа «Too many open files». Явныйwithилиtry/finallyсclose()вfinallyустраняют проблему.
Подводные камни
- Риски. Полагаются на то, что сборщик мусора рано или поздно закроет файл через
__del__, забывая, что это не гарантировано вовремя и не является заменой явного управления ресурсом.