Как "с" лучше, чем try/catch, чтобы открыть файл в Python?
Я понял, что инструкция with
поможет вам сделать это:
try:
f = open(my_file)
do_stuff_that_fails()
except:
pass
finally:
f.close()
В:
with open(my_file) as f:
do_stuff_that_fails()
Но как это лучше? Вы все еще должны обрабатывать дело, когда файл не может быть открыт (например, подскажите пользователю, чтобы он сказал ему, что у него нет разрешений), поэтому на самом деле вы бы:
try:
with open(my_file) as f:
do_stuff_that_fails()
except (IOError, OSError, Failure) as e:
do_stuff_when_it_doesnt_work()
Что эквивалентно:
try:
f = open(my_file)
do_stuff_that_fails()
except (IOError, OSError, Faillure) as e:
do_stuff_when_it_doesnt_work()
finally:
f.close()
Да, вы получили две строки, но вы добавили уровень вложенности, который не упрощает чтение. Является ли цель оператора with
сохранением двух строк или я что-то упускаю?
Кажется, что нужно добавить ключевое слово только для этого, поэтому я чувствую, что есть некоторый синтаксис для обработки дополнительной попытки/кроме того, о которой я не знаю.
Ответы
Ответ 1
Для начала, это поможет предотвратить проблему, которую вы представили в своем примере try ... finally ...
.
Как вы его структурировали, если при попытке открыть файл вызывается исключение, вы никогда не свяжете открытый файл с именем f
, что приведет либо к NameError
в предложении finally
(если f
никогда не было связано в пределах области действия) или что-то совершенно неожиданное (если оно есть).
Правильная структура (эквивалентная with
):
f = open(my_file)
try:
do_stuff_that_fails()
finally:
f.close()
(примечание - нет необходимости в предложении except
, если вам там нечего делать).
Второй пример аналогичным образом неверен и должен быть структурирован следующим образом:
try:
f = open(my_file)
try:
do_stuff_that_fails()
except EXPECTED_EXCEPTION_TYPES as e:
do_stuff_when_it_doesnt_work()
finally:
f.close()
except (IOError, OSError) as e:
do_other_stuff_when_it_we_have_file_IO_problems()
Вторая (как указано в другом ответе), что вы не можете забыть позвонить f.close()
.
BTW, термин "управление контекстом", а не "управление ресурсами" - оператор with
управляет контекстами, некоторые из которых могут быть ресурсами, а другие нет. Например, он также используется с decimal
для создания десятичного контекста для конкретного блока кода.
Наконец (отвечая на ваш комментарий к предыдущему ответу), вы никогда не должны полагаться на семантику refcount для обработки ресурсов в Python. Jython, IronPython и PyPy имеют не-refcount семантику, и ничего не мешает CPython идти другим путем (хотя это маловероятно для ближайшего будущего). В жесткой петле (например, os.walk
) очень просто выбежать из дескрипторов файлов, если код, основанный на семантике refcount, запускается на виртуальной машине с различным поведением.
Ответ 2
В примере, который вы даете, это не лучше. Лучше всего перехватывать исключения как близко к той точке, в которой они выбрасываются, чтобы избежать попадания несвязанных исключений одного и того же типа.
try:
file = open(...)
except OpenErrors...:
# handle open exceptions
else:
try:
# do stuff with file
finally:
file.close()
Как и в случае с этим, оператор with
не позволяет вам исключать исключения, возникшие во время его оценки. Было предложено , чтобы добавить обработку исключений в этот список в список рассылки:
with open(...) as file:
# do stuff with file
except OpenErrors...:
# handle open exceptions
Но это было сбито.
Наконец, стоит отметить, что вы можете напрямую входить и выходить из контекстных менеджеров:
file = open(...).__enter__()
file.__exit__(typ, val, tb)
Это описано более подробно здесь и здесь.
В качестве общего руководства утверждения with
превосходят случаи, когда исключения не ожидаются, и поведение по умолчанию "вводить/открывать/приобретать" является адекватным. Примеры включают требуемые файлы и простую блокировку.
Ответ 3
Это для управления ресурсами... не для того, как вы реагируете на исключение иначе:)
Невозможно "забыть" f.close()
при использовании with
. Таким образом, он выполняет ту же роль, что и using
в С#.
Счастливое кодирование.