5

Зачем в Python нужен блок "finally"?

28

Я не совсем понимаю, зачем нужен блок finally в конструкции try...except...finally. На мой взгляд, вот этот код:

try:
    run_code1()
except TypeError:
    run_code2()
other_code()

товарищ с этим кодом, использующим finally:

try:
    run_code1()
except TypeError:
    run_code2()
finally:
    other_code()

Неужели эти два блока кода по сути одинаковы? Не упустил ли я что-то важное?

5 ответ(ов)

7

Да, ранний возврат действительно имеет значение. Рассмотрим ваш код подробнее.

В первом примере:

try:
    run_code1()
except TypeError:
    run_code2()
    return None   # Блок finally выполняется перед возвратом из метода
finally:
    other_code()

Здесь блок finally обязательно выполнится перед завершением метода, даже если возникнет исключение или будет выполнен возврат из метода. Это означает, что other_code() всегда будет вызван, независимо от того, было ли исключение TypeError или нет.

Теперь сравним это со вторым примером:

try:
    run_code1()
except TypeError:
    run_code2()
    return None   

other_code()  # Этот код не выполнится, если возникнет исключение.

В этом случае, если run_code1() вызовет исключение типа TypeError, блок except выполнится и произойдёт возврат из метода, а other_code() не будет вызван. Таким образом, выполнение кода зависит от того, возвращаем ли мы раньше в блоке except.

Кроме того, есть и другие ситуации, которые могут привести к различиям в поведении:

  • Если исключение возникает внутри блока except, то это может повлиять на исполнение кода.
  • Если run_code1() вызывает исключение, но это не TypeError, тогда код в блоке except не выполнится и other_code() также не будет вызван.
  • Кроме того, такие операторы управления потоком, как continue и break, могут также повлиять на то, как и когда выполняется оставшийся код.

Таким образом, важно обращать внимание на структуру вашего кода и его поведение в случаях исключений для правильного управления потоком выполнения.

0

Чтобы дополнить другие ответы, стоит отметить, что блок finally выполняется в любом случае, а блок else выполняется только в том случае, если исключение не было вызвано.

Например, запись в файл без исключений будет выводить следующее:

file = open('test.txt', 'w')

try:
    file.write("Testing.")
    print("Запись в файл.")
except IOError:
    print("Не удалось записать в файл.")
else:
    print("Запись успешна.")
finally:
    file.close()
    print("Файл закрыт.")

ВЫВОД:

Запись в файл.
Запись успешна.
Файл закрыт.

Если возникает исключение, код выведет следующее (обратите внимание, что ошибка вызвана тем, что файл открыт только для чтения):

file = open('test.txt', 'r')

try:
    file.write("Testing.")
    print("Запись в файл.")
except IOError:
    print("Не удалось записать в файл.")
else:
    print("Запись успешна.")
finally:
    file.close()
    print("Файл закрыт.")

ВЫВОД:

Не удалось записать в файл.
Файл закрыт.

Мы можем видеть, что блок finally выполняется независимо от наличия исключения. Надеюсь, это поможет.

0

Ваша программа демонстрирует работу конструкции try-except-finally в Python. Чтобы прояснить разницу, вот что происходит в различных сценариях:

  1. Случай a, b = 0, 1:
try: 
  a/b
  print('In try block')
  
except TypeError:
  print('In except block')
  
finally: 
  print('In finally block')

print('Outside')

Вывод:

In try block 
In finally block 
Outside

В этом случае не возникает ошибок, поэтому блок except пропускается, и программа продолжает выполнение, доходя до блока finally, а затем выводит 'Outside'.

  1. Случай a, b = 1, 0:
try: 
  a/b
  print('In try block')
  
except TypeError:
  print('In except block')
  
finally: 
  print('In finally block')

print('Outside')

Вывод:

In finally block

Traceback (most recent call last):
a/b
ZeroDivisionError: division by zero

Здесь возникает ошибка деления на ноль. Поскольку нет блока except, обрабатывающего ZeroDivisionError, блок finally выполняется, но программа затем завершает выполнение с ошибкой.

  1. Случай a, b = 0, '1':
try: 
  a/b
  print('In try block')
  
except TypeError:
  print('In except block')
  
finally: 
  print('In finally block')

print('Outside')

Вывод:

In except block 
In finally block 
Outside

В этом примере возникает TypeError, так как вы пытаетесь делить на строку. Исключение перехватывается в блоке except, и программа продолжает выполнение, доходя до блока finally, после чего выводит 'Outside'.

Примечание: Если у вас есть блок except, обрабатывающий все типы ошибок, то блок finally может оказаться избыточным, так как все ошибки будут обработаны в блоке except.

0

Кодовые блоки не эквивалентны. В отличие от первого варианта, в котором other_code() не будет выполнен, если run_code1() выбрасывает исключение, кроме TypeError, или если run_code2() вызывает исключение, блок finally будет выполнен в любом случае. Таким образом, разница заключается в том, что finally выполняется в любом случае, даже если возникает другое исключение, в то время как в первом варианте это не так.

0

В вашем первом примере, что произойдет, если run_code1() вызовет исключение, которое не является TypeError? В этом случае other_code() не будет выполнен.

Сравните это с версией с блоком finally:: other_code() будет гарантированно выполнен, независимо от того, будет ли вызвано какое-либо исключение.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь