Я работаю над сценарием Python, который запускает несколько процессов и соединений с базой данных. Время от времени я хочу убить скрипт с сигналом Ctrl+ C, и я хотел бы сделать некоторую очистку.
В Perl я бы сделал это:
$SIG{'INT'} = 'exit_gracefully';
sub exit_gracefully {
print "Caught ^C \n";
exit (0);
}
Как мне сделать аналог этого в Python?
./program.py > output.log
. Когда вы нажимаете Ctrl-C, вы хотите, чтобы ваша программа корректно завершала работу, регистрируя, что все файлы данных были очищены и помечены как чистые, чтобы подтвердить, что они остались в известном исправном состоянии. Но Ctrl-C отправляет SIGINT всем процессам в конвейере, поэтому оболочка может закрыть STDOUT (теперь «output.log»), прежде чем program.py завершит печать окончательного журнала. Python будет жаловаться: «Не удалось закрыть в деструкторе файлового объекта: Ошибка в sys.excepthook:».Вы можете рассматривать это как исключение (KeyboardInterrupt), как и любое другое. Создайте новый файл и запустите его из вашей оболочки со следующим содержимым, чтобы понять, что я имею в виду:
источник
signal.signal(signal.SIGINT, signal.default_int_handler)
или вы потерпите неудачу, потому что KeyboardInterrupt не срабатывает в каждой ситуации, в которой он должен срабатывать! Подробности здесь .И как менеджер контекста:
Использовать:
Вложенные обработчики:
Отсюда: https://gist.github.com/2907502
источник
StopIteration
чтобы разорвать внутренний цикл при нажатии Ctrl-C, верно?Вы можете обработать CTRL+ C, поймав
KeyboardInterrupt
исключение. Вы можете реализовать любой код очистки в обработчике исключений.источник
Из документации Python :
источник
Еще один фрагмент
Приглашение в
main
качестве основной функции , иexit_gracefully
как CTRL+ cобработчикисточник
Я адаптировал код из @udi для поддержки нескольких сигналов (ничего особенного):
Этот код поддерживает вызов прерывания клавиатуры (
SIGINT
) иSIGTERM
(kill <process>
)источник
В отличие от Мэтта J его ответ, я использую простой объект. Это дает мне возможность анализировать этот обработчик для всех потоков, которые необходимо остановить в секьюритории.
В другом месте
источник
time.sleep()
вместо выполнения занятого цикла для переменной.Вы можете использовать функции во встроенном сигнальном модуле Python для настройки обработчиков сигналов в Python. В частности,
signal.signal(signalnum, handler)
функция используется для регистрацииhandler
функции для сигналаsignalnum
.источник
спасибо за существующие ответы, но добавил
signal.getsignal()
источник
Если вы хотите, чтобы ваш процесс очистки завершился, я бы добавил к ответу Мэтта J, используя SIG_IGN, чтобы дальнейшие действия
SIGINT
игнорировались, что предотвратит прерывание вашей очистки.источник
Лично я не мог использовать try / кроме KeyboardInterrupt, потому что я использовал стандартный режим сокета (IPC), который блокирует. Таким образом, SIGINT был задан, но пришел только после получения данных на сокете.
Установка обработчика сигнала ведет себя так же.
С другой стороны, это работает только для реального терминала. Другие стартовые среды могут не принимать Ctrl+ Cили предварительно обрабатывать сигнал.
Кроме того, в Python есть «Исключения» и «BaseExceptions», которые отличаются в том смысле, что интерпретатору необходимо завершить работу самостоятельно, поэтому некоторые исключения имеют более высокий приоритет, чем другие (исключения получены из BaseException)
источник