Будет ли 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).

Другие вопросы по тегам