Я не уверен, зачем нам finally
в операторах try...except...finally
. На мой взгляд, этот кодовый блок
try:
run_code1()
except TypeError:
run_code2()
other_code()
совпадает с этим с помощью finally
:
try:
run_code1()
except TypeError:
run_code2()
finally:
other_code()
Я что-то пропустил?
Ответ 1
Это имеет значение, если вы вернетесь раньше:
try:
run_code1()
except TypeError:
run_code2()
return None # The finally block is run before the method returns
finally:
other_code()
Сравните с этим:
try:
run_code1()
except TypeError:
run_code2()
return None
other_code() # This doesn't get run if there an exception.
Другие ситуации, которые могут вызывать различия:
- Если исключение выбрано внутри блока except.
- Если исключение выбрано в
run_code1()
, но это не TypeError
.
- Другие операторы потока управления, такие как
continue
и break
.
Ответ 2
Вы можете использовать finally
, чтобы убедиться, что файлы или ресурсы закрыты или выпущены независимо от того, произошло ли исключение, даже если вы не поймаете исключение. (Или если вы не поймаете это конкретное исключение.)
myfile = open("test.txt", "w")
try:
myfile.write("the Answer is: ")
myfile.write(42) # raises TypeError, which will be propagated to caller
finally:
myfile.close() # will be executed before TypeError is propagated
В этом примере вам лучше использовать оператор with
, но такая структура может использоваться для других видов ресурсов.
Несколько лет спустя я написал сообщение в блоге о злоупотреблении finally
, которое читатели могут найти забавным.
Ответ 3
Они не эквивалентны. Наконец, код запускается независимо от того, что еще происходит. Он полезен для кода очистки, который должен выполняться.
Ответ 4
Блоки кода не эквивалентны. Предложение finally
также будет выполняться, если run_code1()
выдает исключение, отличное от TypeError
, или если run_code2()
выдает исключение, а other_code()
в первой версии не будет выполняться в этих случаях.
Ответ 5
В первом примере, что произойдет, если run_code1()
вызывает исключение, которое не является TypeError
?... other_code()
не будет выполняться.
Сравните это с версией finally:
: other_code()
гарантированно будет выполняться независимо от возбуждения любого исключения.
Ответ 6
finally
предназначен для определения "действий очистки" . Предложение finally
выполняется в любом случае перед тем, как оставить оператор try
, произошло ли исключение (даже если вы его не обработали) или нет.
I второй пример @Byers.
Ответ 7
Наконец, можно также использовать, когда вы хотите запустить "необязательный" код перед запуском кода для своей основной работы и что необязательный код может выйти из строя по разным причинам.
В следующем примере мы точно не знаем, какие исключения store_some_debug_info
могут быть выбраны.
Мы могли бы запустить:
try:
store_some_debug_info()
except Exception:
pass
do_something_really_important()
Но большинство линтеров будут жаловаться на то, что ловушка слишком расплывчата из-за исключения. Кроме того, поскольку мы выбираем только pass
для ошибок, блок except
действительно не добавляет значения.
try:
store_some_debug_info()
finally:
do_something_really_important()
Вышеприведенный код имеет тот же эффект, что и первый блок кода, но более краткий.
Ответ 8
Идеальный пример:
try:
#x = Hello + 20
x = 10 + 20
except:
print 'I am in except block'
x = 20 + 30
else:
print 'I am in else block'
x += 1
finally:
print 'Finally x = %s' %(x)
Ответ 9
Как поясняется в документации, предложение finally
предназначено для определения действий по очистке, которые должны выполняться под все обстоятельства.
Если присутствует finally
, он указывает "обработчик очистки". try
выполняется, включая любые предложения except
и else
. Если исключение возникает в любом из предложений и не обрабатывается, исключение временно сохраняется. Выполняется предложение finally
. Если существует сохраненное исключение, которое повторно восстает в конце finally
пункт.
Пример:
>>> def divide(x, y):
... try:
... result = x / y
... except ZeroDivisionError:
... print("division by zero!")
... else:
... print("result is", result)
... finally:
... print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
Как вы можете видеть, предложение finally
выполняется в любом случае. TypeError
, вызванный делением двух строк, не обрабатывается предложением except
и поэтому повторно возникает после выполнения предложения finally
.
В приложениях реального мира предложение finally полезно для освобождения внешних ресурсов (например, файлов или сетевых подключений), независимо от того, успешно ли используется ресурс.
Ответ 10
Чтобы добавить к другим ответам выше, предложение finally
выполняется независимо от того, в то время как предложение else
выполняется только в том случае, если исключение не было создано.
Например, при записи в файл без исключений выводится следующее:
file = open('test.txt', 'w')
try:
file.write("Testing.")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")
ВЫВОД:
Writing to file.
Write successful.
File closed.
Если есть исключение, код выдаст следующее: (обратите внимание, что преднамеренная ошибка вызвана сохранением файла только для чтения.
file = open('test.txt', 'r')
try:
file.write("Testing.")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")
ВЫВОД:
Could not write to file.
File closed.
Мы видим, что предложение finally
выполняется независимо от исключения. Надеюсь, это поможет.