Зачем нам нужно предложение "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()
Я что-то пропустила?
11 ответов
это имеет значение, если вы вернетесь рано:
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's an exception.
другие ситуации, которые могут вызвать различия:
- если исключение выбрасывается внутри блока except.
- если исключение выбрасывается
run_code1()
но это неTypeError
. - другие операторы потока управления, такие как
continue
иbreak
заявления.
можно использовать 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
что читатели могут найти забавным.
Они не эквивалентны. Наконец, код запускается независимо от того, что еще происходит. Это полезно для кода очистки, который должен выполняться.
блоки кода не эквивалентны. The finally
предложение также будет выполняться, если run_code1()
создает исключение, отличное от TypeError
, или run_code2()
выдает исключение, в то время как other_code()
в первой версии не будет работать в этих случаях.
в вашем первом примере, что произойдет, если run_code1()
вызывает исключение, а не TypeError
? ... other_code()
не будет выполнен.
сравните это с finally:
версия: other_code()
гарантированно будет выполняться независимо от любого возникшего исключения.
чтобы добавить к другим ответам выше,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
предложение выполняется независимо от исключения. Надеюсь, это поможет.
finally
для определения "очистить действия". The finally
предложение выполняется в любом случае перед выходом из try
оператор, произошло ли исключение (даже если вы не обрабатываете его) или нет.
Я второй пример @Byers.
наконец, может также использоваться, когда вы хотите запустить "необязательный" код перед запуском кода для основной работы, и этот необязательный код может завершиться неудачей по различным причинам.
в следующем примере, мы не знаем точно, какие исключения 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()
приведенный выше код имеет тот же эффект, как и 1-й блок кода, но более лаконично.
прекрасный пример, как показано ниже:
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)
как поясняется в документация, the finally
предложение предназначено для определения действий очистки, которые должны быть выполнены при всех обстоятельствах.
если
finally
присутствует, он указывает обработчик ‘cleanup’. Thetry
предложение выполняется, в том числе anyexcept
иelse
положения. Если исключение возникает в любом из предложений и не обрабатывается, исключение-временно сохраняется. Thefinally
пункт выполняется. Если существует сохраненное исключение, которое повторно вызывается в конце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
пункт выполняется в любом случае. The TypeError
поднял путем деления двух строк не обрабатывается except
п. и поэтому ре-рейз после finally
предложение выполнено.
в реальных приложениях предложение finally полезно для освобождения внешних ресурсов (таких как файлы или сетевые подключения), независимо от того, было ли использование ресурса успешным.
использование delphi профессионально в течение нескольких лет научило меня защищать мои процедуры очистки, используя, наконец. Delphi в значительной степени обеспечивает использование finally для очистки любых ресурсов, созданных до блока try, чтобы не вызвать утечку памяти. Так же работают Java, Python и Ruby.
resource = create_resource
try:
use resource
finally:
resource.cleanup
и ресурс будет очищен независимо от того, что вы делаете между попробовать и наконец. Кроме того, он не будет очищен, если выполнение никогда не достигает try
блок. (т. е. бросает исключение) это делает ваш код "исключений".
что касается того, почему вам действительно нужен блок finally, не все языки. В C++, где вы автоматически вызываете деструкторы, которые обеспечивают очистку, когда исключение разворачивает стек. Я думаю, что это шаг вперед в направлении более чистого кода по сравнению с try...наконец языки.
{
type object1;
smart_pointer<type> object1(new type());
} // destructors are automagically called here in LIFO order so no finally required.