How do I capture SIGINT in Python?
我正在编写一个启动多个进程和数据库连接的python脚本。我时不时地想用CtrL+C信号终止脚本,我想做一些清理。
在Perl中,我会这样做:
1 2 3 4 5 6 7 | $SIG{'INT'} = 'exit_gracefully'; sub exit_gracefully { print"Caught ^C "; exit (0); } |
如何在Python中进行类似的操作?
向
1 2 3 4 5 6 7 8 9 | #!/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() |
从这里改编的代码。
更多关于
您可以像对待任何其他异常(键盘中断)一样对待它。创建一个新文件,并从shell运行它,其中包含以下内容,以了解我的意思:
1 2 3 4 5 6 7 8 9 10 11 | import time, sys x = 1 while True: try: print x time.sleep(.3) x += 1 except KeyboardInterrupt: print"Bye" sys.exit() |
作为上下文管理器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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 |
使用:
1 2 3 4 5 6 7 8 | with GracefulInterruptHandler() as h: for i in xrange(1000): print"..." time.sleep(1) if h.interrupted: print"interrupted!" time.sleep(2) break |
嵌套处理程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
从这里:https://gist.github.com/2907502
您可以通过捕获
从python的文档中:
1 2 3 4 5 6 7 8 9 | import signal import time def handler(signum, frame): print 'Here you go' signal.signal(signal.SIGINT, handler) time.sleep(10) # Press Ctrl+c here |
又一个片段
将
1 2 3 4 5 6 7 | if __name__ == '__main__': try: main() except KeyboardInterrupt: pass finally: exit_gracefully() |
我修改了@udi的代码以支持多个信号(没什么特别之处):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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 |
此代码支持键盘中断调用(
与Matt J的答案不同,我使用的是一个简单的物体。这使我能够将这个处理程序解析为所有需要安全停止的线程。
1 2 3 4 5 6 7 8 9 10 11 | 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) |
别处
1 2 3 4 | while True: # task if handler.SIGINT: break |
您可以使用Python内置信号模块中的函数在Python中设置信号处理程序。具体来说,
感谢现有答案,但添加了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import signal # store default handler of signal.SIGINT default_handler = signal.getsignal(signal.SIGINT) catch_count = 0 def handler(signum, frame): global default_handler, catch_count catch_count += 1 print ('wait:', catch_count) if catch_count > 3: # recover handler for signal.SIGINT signal.signal(signal.SIGINT, default_handler) print('expecting KeyboardInterrupt') signal.signal(signal.SIGINT, handler) print('Press Ctrl+c here') while True: pass |
就我个人而言,我不能使用Try/Except键盘中断,因为我使用的是阻塞的标准套接字(IPC)模式。所以这个信号是被提示的,但只有在接收到套接字上的数据之后才会出现。
设置信号处理程序的行为相同。
另一方面,这只适用于实际的终端。其他启动环境可能不接受ctrl+c或预处理信号。
另外,在python中还有"exceptions"和"baseexceptions",这两个术语在解释程序需要自己干净地退出的意义上有所不同,因此某些异常的优先级高于其他异常(异常是从baseexception派生的)。