Как я могу захватить SIGINT в Python?
Я работаю на Python-скрипт, который запускает несколько процессов и подключений к базе данных. Время от времени я хочу убить скрипт с помощью Ctrl+C сигнал, и я хотел бы сделать некоторые очистки.
в Perl я бы сделал так:
$SIG{'INT'} = 'exit_gracefully';
sub exit_gracefully {
print "Caught ^C n";
exit (0);
}
Как мне сделать аналог этого в Python?
9 ответов:
зарегистрируйте свой обработчик с помощью
signal.signalтакой:#!/usr/bin/env python import signal import sys def signal_handler(sig, frame): print('You pressed Ctrl+C!') sys.exit(0) signal.signal(signal.SIGINT, signal_handler) print('Press Ctrl+C') signal.pause()код адаптирован из здесь.
дополнительная документация по
signalможно найти здесь.
вы можете рассматривать его как исключение (KeyboardInterrupt), как и любой другой. Сделайте новый файл и запустите его из своей оболочки со следующим содержимым, чтобы увидеть, что я имею в виду:
import time, sys x = 1 while True: try: print x time.sleep(.3) x += 1 except KeyboardInterrupt: print "Bye" sys.exit()
и как менеджер контекста:
import signal class GracefulInterruptHandler(object): def __init__(self, sig=signal.SIGINT): self.sig = sig def __enter__(self): self.interrupted = False self.released = False self.original_handler = signal.getsignal(self.sig) def handler(signum, frame): self.release() self.interrupted = True signal.signal(self.sig, handler) return self def __exit__(self, type, value, tb): self.release() def release(self): if self.released: return False signal.signal(self.sig, self.original_handler) self.released = True return Trueиспользование:
with GracefulInterruptHandler() as h: for i in xrange(1000): print "..." time.sleep(1) if h.interrupted: print "interrupted!" time.sleep(2) breakвложенные обработчики:
with GracefulInterruptHandler() as h1: while True: print "(1)..." time.sleep(1) with GracefulInterruptHandler() as h2: while True: print "\t(2)..." time.sleep(1) if h2.interrupted: print "\t(2) interrupted!" time.sleep(2) break if h1.interrupted: print "(1) interrupted!" time.sleep(2) break
вы можете справиться CTRL+C, ловя
KeyboardInterruptисключения. В обработчике исключений можно реализовать любой код очистки.
от Python документация:
import signal import time def handler(signum, frame): print 'Here you go' signal.signal(signal.SIGINT, handler) time.sleep(10) # Press Ctrl+c here
Еще Один Фрагмент
называют
mainкак основная функция иexit_gracefullyкак CTRL + c проводникif __name__ == '__main__': try: main() except KeyboardInterrupt: pass finally: exit_gracefully()
я адаптировал код из @udi для поддержки нескольких сигналов (ничего необычного):
class GracefulInterruptHandler(object): def __init__(self, signals=(signal.SIGINT, signal.SIGTERM)): self.signals = signals self.original_handlers = {} def __enter__(self): self.interrupted = False self.released = False for sig in self.signals: self.original_handlers[sig] = signal.getsignal(sig) signal.signal(sig, self.handler) return self def handler(self, signum, frame): self.release() self.interrupted = True def __exit__(self, type, value, tb): self.release() def release(self): if self.released: return False for sig in self.signals: signal.signal(sig, self.original_handlers[sig]) self.released = True return Trueэтот код поддерживает вызов прерывания клавиатуры (
SIGINT) иSIGTERM(kill <process>)
вы можете использовать функции в Python встроенный модуль сигнала для настройки обработчиков сигналов в python. В частности,
signal.signal(signalnum, handler)функция используется для регистрацииhandlerфункции для сигналаsignalnum.
В отличие от Matt J его ответ, я использую простой объект. Это дает мне возможность проанализировать этот обработчик для всех потоков, которые должны быть остановлены securlery.
class SIGINT_handler(): def __init__(self): self.SIGINT = False def signal_handler(self, signal, frame): print('You pressed Ctrl+C!') self.SIGINT = True handler = SIGINT_handler() signal.signal(signal.SIGINT, handler.signal_handler)в другом месте
while True: # task if handler.SIGINT: break
Comments