How do I capture SIGINT in Python?

前端 未结 12 1495
长发绾君心
长发绾君心 2020-11-21 22:54

I\'m working on a python script that starts several processes and database connections. Every now and then I want to kill the script with a Ctrl+C sign

相关标签:
12条回答
  • 2020-11-21 23:10

    You can handle CTRL+C by catching the KeyboardInterrupt exception. You can implement any clean-up code in the exception handler.

    0 讨论(0)
  • 2020-11-21 23:10

    From Python's 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
    
    0 讨论(0)
  • 2020-11-21 23:11

    And as a context manager:

    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
    

    To use:

    with GracefulInterruptHandler() as h:
        for i in xrange(1000):
            print "..."
            time.sleep(1)
            if h.interrupted:
                print "interrupted!"
                time.sleep(2)
                break
    

    Nested handlers:

    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
    

    From here: https://gist.github.com/2907502

    0 讨论(0)
  • 2020-11-21 23:12

    Yet Another Snippet

    Referred main as the main function and exit_gracefully as the CTRL + c handler

    if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            pass
        finally:
            exit_gracefully()
    
    0 讨论(0)
  • 2020-11-21 23:16

    I adapted the code from @udi to support multiple signals (nothing fancy) :

    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
    

    This code support the keyboard interrupt call (SIGINT) and the SIGTERM (kill <process>)

    0 讨论(0)
  • 2020-11-21 23:20

    Personally, I couldn't use try/except KeyboardInterrupt because I was using standard socket (IPC) mode which is blocking. So the SIGINT was cueued, but came only after receiving data on the socket.

    Setting a signal handler behaves the same.

    On the other hand, this only works for an actual terminal. Other starting environments might not accept Ctrl+C, or pre-handle the signal.

    Also, there are "Exceptions" and "BaseExceptions" in Python, which differ in the sense that interpreter needs to exit cleanly itself, so some exceptions have a higher priority than others (Exceptions is derived from BaseException)

    0 讨论(0)
提交回复
热议问题