首页 文章

如何在Python中捕获SIGINT?

提问于
浏览
443

我正在开发一个启动多个进程和数据库连接的python脚本 . 我不时地想用Ctrl C信号杀死脚本,我想做一些清理工作 .

在Perl我会这样做:

$SIG{'INT'} = 'exit_gracefully';

sub exit_gracefully {
    print "Caught ^C \n";
    exit (0);
}

我如何在Python中模拟这个?

10 回答

  • 3

    使用 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()
    

    代码改编自here .

    有关 signal 的更多文档可以在here找到 .

  • 4

    您可以将其视为异常(KeyboardInterrupt),就像任何其他异常一样 . 创建一个新文件并使用以下内容从shell运行它以查看我的意思:

    import time, sys
    
    x = 1
    while True:
        try:
            print x
            time.sleep(.3)
            x += 1
        except KeyboardInterrupt:
            print "Bye"
            sys.exit()
    
  • 18

    作为上下文管理器:

    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
    

    从这里:https://gist.github.com/2907502

  • 649

    您可以通过捕获 KeyboardInterrupt 异常来处理CTRL C.您可以在异常处理程序中实现任何清理代码 .

  • 0

    来自Python的documentation

    import signal
    import time
    
    def handler(signum, frame):
        print 'Here you go'
    
    signal.signal(signal.SIGINT, handler)
    
    time.sleep(10) # Press Ctrl+c here
    
  • 13

    又一个片段

    main 称为主函数,将 exit_gracefully 称为CTRL c处理程序

    if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            pass
        finally:
            exit_gracefully()
    
  • 7

    我调整了@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 )和 SIGTERMkill <process>

  • 26

    您可以使用Python内置的signal module中的函数在python中设置信号处理程序 . 具体来说, signal.signal(signalnum, handler) 函数用于为信号 signalnum 注册 handler 函数 .

  • 56

    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
    
  • 145

    就个人而言,我无法使用try / except KeyboardInterrupt,因为我使用的是阻塞的标准套接字(IPC)模式 . 所以SIGINT被提示了,但只是在接收到套接字上的数据后才出现 .

    设置信号处理程序的行为相同 .

    另一方面,这仅适用于实际终端 . 其他启动环境可能不接受Ctrl C或预处理信号 .

    此外,Python中有“Exceptions”和“BaseExceptions”,它们在解释器需要自己完全退出的意义上有所不同,因此一些异常具有比其他异常更高的优先级(Exceptions派生自BaseException)

相关问题