关于try catch:在没有try-except的情况下在Python中捕获keyboardinterrupt

Capture keyboardinterrupt in Python without try-except

在python中,是否有某种方法可以捕获KeyboardInterrupt事件而不将所有代码放在tryexcept语句中?

如果用户按ctrl+c,我希望完全退出而不进行跟踪。


是的,您可以使用模块信号安装中断处理程序,并使用线程永久等待。事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
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
2
3
4
5
6
7
8
9
10
11
## all your app logic here
def main():
   ## whatever your app does.


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

(是的,我知道这并不能直接回答这个问题,但不清楚为什么需要一个try/except块是令人讨厌的——也许这会使操作不那么烦人)


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

1
2
3
4
5
6
7
8
9
10
11
12
>>> 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清理时所寻找的。只是想用另一种方式来解决这个问题。

我想在织物操作的背景下进行出口后清理,所以用tryexcept包装所有东西也不是我的选择。我觉得atexit可能很适合这种情况,在这种情况下,您的代码不在控制流的顶层。

atexit是一种非常有能力和可读性的开箱即用产品,例如:

1
2
3
4
5
6
import atexit

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

atexit.register(goodbye)

您也可以将其用作修饰器(从2.6开始;此示例来自文档):

1
2
3
4
5
import atexit

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

如果你只想把它具体化到KeyboardInterrupt,那么另一个人对这个问题的回答可能会更好。

但是请注意,atexit模块只有大约70行代码,因此不难创建一个处理异常不同的类似版本,例如将异常作为参数传递给回调函数。(需要修改版本的atexit的限制:目前我想不出一种方法让exit回调函数知道异常;atexit处理程序捕获异常,调用回调,然后重新引发该异常。但你可以用不同的方法来做。)

有关详细信息,请参阅:

  • 关于atexit的正式文件
  • 周帖的python模块,很好的介绍


如果没有try: ... except KeyboardInterrupt: pass(最明显和最好的"最佳"解决方案,但您已经知道并要求其他解决方案),可以通过替换sys.excepthook来防止打印KeyboardInterrupt的堆栈跟踪。有点像

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