Будет ли Python выполнять, наконец, блок после получения Ctrl+C
Если вы остановите скрипт python с помощью Ctrl+C, он выполнит какие-нибудь блоки finally или буквально остановит скрипт там, где он находится?
4 ответа
Ну, ответ в основном это зависит. Вот что на самом деле происходит:
- Python выполняет код в
try:... finally:
блок - Ctrl-C испускается и переводится в исключение KeyboardInterrupt
- обработка прерывается и управление переходит к блоку finally
Так что на первый взгляд все работает как положено. Но...
Когда пользователь (не вы, а другие...) хочет прервать задачу, он обычно нажимает несколько раз Ctrl-C. Первый ответвит выполнение в finally
блок. Если в середине блока finally происходит еще одно нажатие клавиши Ctrl-C, поскольку оно содержит медленные операции, такие как закрытие файлов, будет вызвано новое KeyboardInterrupt, и ничто не гарантирует, что весь блок будет выполнен, и вы можете получить что-то вроде:
Traceback (most recent call last):
File "...", line ..., in ...
...
KeyboardInterrupt
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "...", line ..., in ...
...
File "...", line ..., in ...
...
KeyboardInterrupt
Да, при условии единственного Ctrl+C, по крайней мере, под Linux это будет. Вы можете проверить это с помощью следующего кода Python 3:
import time
try:
print('In try.')
time.sleep(1000)
finally:
print(' <-- Note the Ctrl+C.')
for i in range(1, 6):
print('Finishing up part {} of 5.'.format(i))
time.sleep(.1)
Вот вывод:
$ ./finally.py
In try.
^C <-- Note the Ctrl+C.
Finishing up part 1 of 5.
Finishing up part 2 of 5.
Finishing up part 3 of 5.
Finishing up part 4 of 5.
Finishing up part 5 of 5.
Traceback (most recent call last):
File "./finally.py", line 7, in <module>
time.sleep(1000)
KeyboardInterrupt
Да, обычно он вызывает исключение KeyboardInterrupt, но помните, что ваше приложение может быть неожиданно завершено в любое время, поэтому вам не следует полагаться на это.
По умолчанию блоки будут запускаться после сочетания клавиш Ctrl-C, как и в других ответах. Однако, если кто-то переопределил поведение Python по умолчанию, пытаясь «избежать уродливых обратных трассировок KeyboardInterrupt», тогдаfinally
блоки не запускаются.
Я видел это с помощьюsignal.signal(signal.SIGINT, signal.SIG_DFL)
. Это приведет к немедленному завершению работы приложения без какой-либо очистки, как только будет обнаружено прерывание. Насколько я могу судить, этот обработчик сигнала даже не удосужился вызватьKeyboardInterrupt
. Стандартное поведение можно восстановить, удалив указанную выше строку или добавивsignal.signal(signal.SIGINT, signal.default_int_handler)
.