问题:无需尝试即可在Python中捕获键盘中断
Python中是否有某种方法可以捕获KeyboardInterrupt
事件而不将所有代码放入try
– except
语句中?
如果用户按下Ctrl+,我想干净无痕地退出C。
回答 0
是的,您可以使用模块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
如果您只想不显示回溯,则使代码如下所示:
## 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
设置自己的信号处理程序的另一种方法是使用上下文管理器来捕获异常并忽略它:
>>> 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
我知道这是一个古老的问题,但是我首先来到这里,然后发现了该atexit
模块。我还不知道它的跨平台跟踪记录或完整的警告说明,但是到目前为止,这正是我KeyboardInterrupt
在Linux上尝试进行后期清理时一直在寻找的东西。只是想以另一种方式解决问题。
我想在Fabric操作的上下文中进行退出后清理,因此将所有内容都包装在try
/ except
中对我来说也不是一种选择。我觉得atexit
这种情况可能非常适合,因为您的代码不在控制流的最高级别。
atexit
具有非常强大的功能并且易于使用,例如:
import atexit
def goodbye():
print "You are now leaving the Python sector."
atexit.register(goodbye)
您还可以将其用作装饰器(从2.6开始;该示例来自docs):
import atexit
@atexit.register
def goodbye():
print "You are now leaving the Python sector."
如果您只想使其特定KeyboardInterrupt
,那么另一个人对此问题的答案可能会更好。
但是请注意,该atexit
模块只有约70行代码,并且创建类似版本以不同方式对待异常(例如将异常作为参数传递给回调函数)并不难。(这样做的局限性是atexit
需要修改后的版本:目前,我无法为exit-callback-functions知道异常的方法;atexit
处理程序捕获异常,调用回调,然后重新引发该exceptions。但是您可以采取不同的方法。)
有关更多信息,请参见:
- 官方文件
atexit
- 该周后的Python模块,一个很好的介绍
回答 4
您可以通过替换来防止打印堆栈跟踪KeyboardInterrupt
,而无需try: ... except KeyboardInterrupt: pass
(最明显,最恰当的“最佳”解决方案,但您已经知道并要求其他东西)sys.excepthook
。就像是
def custom_excepthook(type, value, traceback):
if type is KeyboardInterrupt:
return # do nothing
else:
sys.__excepthook__(type, value, traceback)
回答 5
我尝试了每个人提出的建议解决方案,但我必须自己临时编写代码才能真正起作用。以下是我的即兴代码:
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
如果有人正在寻找快速的最小解决方案,
import signal
# The code which crashes program on interruption
signal.signal(signal.SIGINT, call_this_function_if_interrupted)
# The code skipped if interrupted