2010-11-17 124 views

回答

122

是的,您可以使用signal module安裝中斷處理程序。

import signal 
import sys 
import time 

def signal_handler(signal, frame): 
    print 'You pressed Ctrl+C!' 
    sys.exit(0) 

signal.signal(signal.SIGINT, signal_handler) 
print 'Press Ctrl+C' 
while True: 
    time.sleep(1) 
+8

請注意,有一些平臺特定的問題與信號模塊 - 不應該影響這張海報,但「在Windows上,信號()只能用SIGABRT,SIGFPE,SIGILL,SIGINT,SIGSEGV或SIGTERM來調用,任何其他情況下都會引發ValueError。 – bgporter 2010-11-17 14:39:11

+6

也適用於線程。儘管如此,我希望你永遠不要「真實:繼續」。 (按照這種風格,無論如何,'雖然真實:通過'會更整潔。)那太浪費了;嘗試類似'while True:time.sleep(60 * 60 * 24)'(一次睡一天完全是任意圖)。 – 2011-10-06 12:04:30

+1

如果你使用克里斯摩根的建議,使用'時間'(如你應該),不要忘了'進口時間':) – Seaux 2013-05-30 17:37:04

4

您可以防止打印堆棧跟蹤KeyboardInterrupt,沒有try: ... except KeyboardInterrupt: pass(最明顯和最propably「最佳」的解決方案,但你已經知道了,問其他的東西),用sys.excepthook。類似於

def custom_excepthook(type, value, traceback): 
    if type is KeyboardInterrupt: 
     return # do nothing 
    else: 
     sys.__excepthook__(type, value, traceback) 
+0

我想幹淨退出,不留痕跡如果用戶按ctrl-c – Alex 2010-11-17 14:29:43

+0

catched ==>抓到 – 2010-11-17 14:51:26

+7

這根本不是真的。 KeyboardInterrupt異常是在中斷處理程序中創建的。 SIGINT的默認處理程序引發了KeyboardInterrupt,所以如果您不想要這種行爲,您只需爲SIGINT提供一個不同的信號處理程序。你的觀點是正確的,只有在嘗試中才能處理異常情況,但是在這種情況下,你可以將異常從頭開始。 – Matt 2012-12-20 14:17:50

25

如果你想要的是不顯示的回溯,使你的代碼是這樣的:

## all your app logic here 
def main(): 
    ## whatever your app does. 


if __name__ == "__main__": 
    try: 
     main() 
    except KeyboardInterrupt: 
     # do nothing here 
     pass 

(是的,我知道這並不直接回答這個問題,但它不是真的清楚爲什麼需要嘗試/除了塊是令人反感的 - 也許這使得它不那麼煩人的OP)

+2

出於某種原因,這並不總是適用於我。 'signal.signal(signal.SIGINT,lambda s,f:sys.exit(0))'總是這樣。 – 2013-07-13 18:15:18

+0

這並不總是適用於諸如使用線程的pygtk之類的東西。有時^ C只會殺死當前線程而不是整個進程,所以異常只會通過該線程傳播。 – 2013-10-23 01:56:45

+0

還有另外一個特別關於Ctrl + C與pygtk的問題:http://stackoverflow.com/questions/16410852/keyboard-interrupt-with-with-python-gtk – bgporter 2013-10-23 13:46:56

23

設置自己的信號處理程序的替代方法是使用上下文管理器來捕獲異常並忽略它:

>>> class CleanExit(object): 
...  def __enter__(self): 
...    return self 
...  def __exit__(self, exc_type, exc_value, exc_tb): 
...    if exc_type is KeyboardInterrupt: 
...      return True 
...    return exc_type is None 
... 
>>> with CleanExit(): 
...  input() #just to test it 
... 
>>> 

這將刪除try - except塊,同時保留一些明確提及正在發生的事情。

這也允許您只在代碼的某些部分忽略中斷,而不必每次都設置和重新設置信號處理程序。

+1

很好,這個解決方案確實似乎有點直接表達目的而不是處理信號。 – Seaux 2013-05-30 17:50:01

4

我知道這是一個老問題,但我先來到這裏,然後發現atexit模塊。我不知道它的跨平臺跟蹤記錄或完整的注意事項,但到目前爲止,它正是我在試圖處理Linux上的後清理操作時所需要的。只是想用另一種方式來解決問題。

我想在Fabric操作的上下文中進行出口後清理,因此在try/except中包裝所有內容對我來說也不是一種選擇。我覺得atexit可能非常適合這種情況,您的代碼不在控制流的頂層。

atexit是非常有能力和可讀性開箱,例如:

import atexit 

def goodbye(): 
    print "You are now leaving the Python sector." 

atexit.register(goodbye) 

您也可以使用它作爲一個裝飾(如2.6;本實施例中是從文檔):

import atexit 

@atexit.register 
def goodbye(): 
    print "You are now leaving the Python sector." 

如果您只想針對KeyboardInterrupt而設定,另一個人對此問題的回答可能會更好。

但請注意,atexit模塊只有70行代碼,創建類似的版本以不同的方式處理異常(例如將異常作爲參數傳遞給回調函數)並不困難。(限制atexit這將保證修改版本:目前我無法想象退出回調函數知道異常的方法; atexit處理程序捕獲異常,調用您的回調,然後重新調用。-raises是例外,但你可以做不同的這個)

欲瞭解更多信息,請參閱: