在没有try-except的情况下捕获Python中的keyboardinterrupt

时间:2010-11-17 14:24:52

标签: python try-catch keyboardinterrupt

Python中是否有某种方法可以捕获KeyboardInterrupt事件而不将所有代码放在try - except语句中?

如果用户按 Ctrl + C ,我想干净利落地退出。

7 个答案:

答案 0 :(得分:139)

是的,您可以使用模块signal安装中断处理程序,并使用threading.Event永远等待:

import signal
import sys
import time
import threading

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

signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
forever = threading.Event()
forever.wait()

答案 1 :(得分:33)

如果你想要的只是不显示回溯,请按照以下方式编写代码:

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


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

(是的,我知道这并没有直接回答这个问题,但是为什么需要一个try / except块是令人反感的并不是很清楚 - 也许这会让它对OP不那么烦恼)

答案 2 :(得分:28)

设置自己的信号处理程序的另一种方法是使用上下文管理器来捕获异常并忽略它:

>>> 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块,同时保留明确提及的内容。

这也允许您仅在代码的某些部分忽略中断,而不必每次都设置和重置信号处理程序。

答案 3 :(得分:6)

我知道这是一个老问题,但我先来到这里,然后发现了atexit模块。我不知道它的跨平台跟踪记录或完整的警告列表,但到目前为止,它正是我在寻求处理Linux上的KeyboardInterrupt清理后所寻求的。只是想提出另一种解决问题的方法。

我想在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处理程序捕获异常,调用你的回调,然后重新提出那个例外。但你可以这样做。)

有关详细信息,请参阅:

答案 4 :(得分:4)

您可以通过替换{{3}来阻止打印KeyboardInterrupt的堆栈跟踪,而不是try: ... except KeyboardInterrupt: pass(最明显且最可靠的“最佳”解决方案,但您已经知道并要求其他内容) }}。像

这样的东西
def custom_excepthook(type, value, traceback):
    if type is KeyboardInterrupt:
        return # do nothing
    else:
        sys.__excepthook__(type, value, traceback)

答案 5 :(得分:2)

我尝试了每个人提出的建议解决方案,但是我必须自己临时编写代码才能真正起作用。以下是我的即兴代码:

import signal
import sys
import time

def signal_handler(signal, frame):
    print('You pressed Ctrl+C!')
    print(signal) # Value is 2 for CTRL + C
    print(frame) # Where your execution of program is at moment - the Line Number
    sys.exit(0)

#Assign Handler Function
signal.signal(signal.SIGINT, signal_handler)

# Simple Time Loop of 5 Seconds
secondsCount = 5
print('Press Ctrl+C in next '+str(secondsCount))
timeLoopRun = True 
while timeLoopRun:  
    time.sleep(1)
    if secondsCount < 1:
        timeLoopRun = False
    print('Closing in '+ str(secondsCount)+ ' seconds')
    secondsCount = secondsCount - 1

答案 6 :(得分:0)

如果有人正在寻找快速的最小解决方案,

import signal

# The code which crashes program on interruption

signal.signal(signal.SIGINT, call_this_function_if_interrupted)

# The code skipped if interrupted