Capture keyboardinterrupt in Python without try-except

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

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

138131 次浏览

You can prevent printing a stack trace for KeyboardInterrupt, without try: ... except KeyboardInterrupt: pass (the most obvious and propably "best" solution, but you already know it and asked for something else) by replacing sys.excepthook. Something like

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

是的,你可以使用模块 信号安装一个 interrupt handler,然后使用 线程,事件永远等待:

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()

如果您想要的只是不显示回溯,那么将您的代码设置为:

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




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

(是的,我知道这并不能直接回答这个问题,但是我们并不清楚为什么需要 try/other 块是令人反感的——也许这使得它对 OP 来说不那么令人讨厌)

An alternative to setting your own signal handler is to use a context-manager to catch the exception and ignore it:

>>> 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块,同时保留对正在发生的事情的一些显式提及。

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

我知道这是一个老问题,但我来到这里第一,然后发现了 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处理程序捕获异常,调用您的回调,然后重新引发该异常。但你可以用不同的方式来做这件事。)

更多信息见:

我尝试了每个人提出的解决方案,但我不得不自己即兴编写代码,以使其真正发挥作用。以下是我的即兴代码:

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