代码之家  ›  专栏  ›  技术社区  ›  James Thompson

如何在python中捕获sigint?

  •  454
  • James Thompson  · 技术社区  · 15 年前

    我正在编写一个启动多个进程和数据库连接的python脚本。偶尔我想用一个 Ctrl键 + C 信号,我想做些清理。

    在Perl中,我会这样做:

    $SIG{'INT'} = 'exit_gracefully';
    
    sub exit_gracefully {
        print "Caught ^C \n";
        exit (0);
    }
    

    如何在Python中进行类似的操作?

    11 回复  |  直到 6 年前
        1
  •  667
  •   Grimthorr Roland77    6 年前

    将处理程序注册到 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 .

        2
  •  147
  •   rledley    15 年前

    您可以像对待任何其他异常(键盘中断)一样对待它。创建一个新文件,并从shell运行它,其中包含以下内容,以了解我的意思:

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

    作为上下文管理器:

    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

        4
  •  26
  •   Mwiza Nagarjuna Durgam    7 年前

    你可以处理 CTRL + C 通过抓住 KeyboardInterrupt 例外。您可以在异常处理程序中实现任何清理代码。

        5
  •  19
  •   pradyunsg ThisIsAQuestion    10 年前

    从蟒蛇的 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
    
        6
  •  13
  •   Jossef Harush Kadouri    9 年前

    又一个片段

    援引的 main 作为主要功能和 exit_gracefully 作为 CTRL + C 处理程序

    if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            pass
        finally:
            exit_gracefully()
    
        7
  •  7
  •   Cyril N.    9 年前

    我修改了@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> )

        8
  •  4
  •   Brandon E Taylor    15 年前

    您可以使用Python内置的函数 signal module 在python中设置信号处理程序。特别是 signal.signal(signalnum, handler) 函数用于注册 handler 信号功能 signalnum .

        9
  •  3
  •   Community CDub    8 年前

    与…对比 Matt J 他的回答是,我用一个简单的物体。这使我能够将这个处理程序解析为所有需要安全停止的线程。

    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
    
        10
  •  0
  •   Ate Somebits    6 年前

    就我个人而言,我不能使用Try/Except键盘中断,因为我使用的是阻塞的标准套接字(IPC)模式。所以这个信号是被提示的,但只有在接收到套接字上的数据之后才会出现。

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

    另一方面,这只适用于实际的终端。其他启动环境可能不接受ctrl+c或预处理信号。

    另外,在python中还有“exceptions”和“baseexceptions”,这两个术语在解释程序需要自己干净地退出的意义上有所不同,因此某些异常的优先级高于其他异常(异常是从baseexception派生的)。

        11
  •  0
  •   gsw945    6 年前

    感谢现有答案,但添加了 signal.getsignal()

    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