2009-07-10 37 views
393

我正在研究啓動多個進程和數據庫連接的python腳本。我不時地想用Ctrl + C信號殺死腳本,我想做一些清理工作。如何在Python中捕獲SIGINT?

在Perl我應該這樣做:

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

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

我怎麼做的這個Python中模擬?

+3

請一定要看到:http://blip.tv/file/2232410(Mindblowing Python的GIL)將線程和信號(如果您有沒有的課程)前。幻燈片在這裏:http://www.dabeaz.com/python/GIL.pdf。 – 2009-07-11 00:17:26

回答

561

signal.signal這樣註冊您的處理程序:

#!/usr/bin/env python 
import signal 
import sys 
def signal_handler(signal, frame): 
     print('You pressed Ctrl+C!') 
     sys.exit(0) 
signal.signal(signal.SIGINT, signal_handler) 
print('Press Ctrl+C') 
signal.pause() 

代碼改編自here

關於signal的更多文檔可以在here找到。

+0

-1表示無限循環。請參閱Chad關於signal.pause()的回答,並請更新。 – Shabbyrobe 2011-02-21 07:35:06

+60

不清楚爲什麼不能在演示代碼中無限循環,但無論如何都要更新。 – 2011-02-23 05:52:26

+8

你能告訴我爲什麼用這個來代替KeyboardInterrupt異常嗎?這不是更直觀的使用? – noio 2011-06-10 14:07:25

21

您可以通過捕捉KeyboardInterrupt例外處理CTRL +Ç。您可以在異常處理程序中實現任何清理代碼。

136

您可以像對待其他任何異常一樣對待它(KeyboardInterrupt)。創建一個新的文件,並從具有以下內容你的shell中運行它,看看我的意思是:

import time, sys 

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

您可以使用的功能Python的內置signal module設立信號處理的蟒蛇。具體來說,signal.signal(signalnum, handler)函數用於註冊信號signalnumhandler函數。

17

從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 
49

而作爲一個上下文管理器:

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

9

然而,另一個片段

簡稱main爲主要功能和exit_gracefully作爲CTRL +ç處理

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

我改編自@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>

2

相反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 
相關問題