Для начала, это поможет предотвратить проблему, которую вы представили в своем примере 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()
.
Кстати, термин «управление контекстом», а не «управление ресурсами» - оператор with
управляет контекстами , некоторые из которых могут быть ресурсами, но другие - нет. Например, он также используется с decimal
для установки десятичного контекста для определенного блока кода.
Наконец (отвечая на ваш комментарий к предыдущему ответу), вы никогда не должны полагаться на семантику refcount для обработки ресурсов в Python. Jython, IronPython и PyPy имеют семантику не-refcount, и ничто не мешает CPython пойти другим путем (хотя в ближайшем будущем это маловероятно). В замкнутом цикле (например, os.walk
) очень легко выйти из файловых дескрипторов, если код, основанный на семантике refcount, выполняется на ВМ с другим поведением.