Зачем нам нужен термин "finally" в Python?

Я не уверен, зачем нам 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 выполняется независимо от исключения. Надеюсь, это поможет.