在没有 try-except 的情况下在 Python 中捕获键盘中断
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4205317/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Capture keyboardinterrupt in Python without try-except
提问by Alex
Is there some way in Python to capture KeyboardInterruptevent without putting all the code inside a try-exceptstatement?
Python 中是否有某种方法可以在KeyboardInterrupt不将所有代码放在try-except语句中的情况下捕获事件?
I want to cleanly exit without trace if user presses Ctrl+C.
如果用户按下Ctrl+ ,我想干净地退出而不留痕迹C。
采纳答案by Johan Kotlinski
Yes, you can install an interrupt handler using the module signal, and wait forever using a threading.Event:
是的,您可以使用模块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()
回答by Alex
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
您可以防止打印堆栈跟踪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)
回答by bgporter
If all you want is to not show the traceback, make your code like this:
如果您只想不显示回溯,请使您的代码如下:
## all your app logic here
def main():
## whatever your app does.
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
# do nothing here
pass
(Yes, I know that this doesn't directly answer the question, but it's not really clear why needing a try/except block is objectionable -- maybe this makes it less annoying to the OP)
(是的,我知道这并没有直接回答这个问题,但不清楚为什么需要一个 try/except 块是令人反感的——也许这会让 OP 不那么烦人)
回答by Bakuriu
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
...
>>>
This removes the try-exceptblock while preserving some explicit mention of what is going on.
这删除了try-except块,同时保留了对正在发生的事情的一些明确提及。
This also allows you to ignore the interrupt only in some portions of your code without having to set and reset again the signal handlers everytime.
这也允许您仅在代码的某些部分忽略中断,而不必每次都再次设置和重置信号处理程序。
回答by driftcatcher
I know this is an old question but I came here first and then discovered the atexitmodule. I do not know about its cross-platform track record or a full list of caveats yet, but so far it is exactly what I was looking for in trying to handle post-KeyboardInterruptcleanup on Linux. Just wanted to throw in another way of approaching the problem.
我知道这是一个老问题,但我先来到这里然后发现了该atexit模块。我还不知道它的跨平台跟踪记录或完整的警告列表,但到目前为止,它正是我KeyboardInterrupt在 Linux 上尝试处理后清理时所寻找的。只是想以另一种方式解决问题。
I want to do post-exit clean-up in the context of Fabric operations, so wrapping everything in try/exceptwasn't an option for me either. I feel like atexitmay be a good fit in such a situation, where your code is not at the top level of control flow.
我想在 Fabric 操作的上下文中进行退出后清理,因此将所有内容都包装在try/except中也不是我的选择。我觉得atexit可能很适合这种情况,您的代码不在控制流的顶层。
atexitis very capable and readable out of the box, for example:
atexit非常有能力并且开箱即用,例如:
import atexit
def goodbye():
print "You are now leaving the Python sector."
atexit.register(goodbye)
You can also use it as a decorator (as of 2.6; this example is from the docs):
您还可以将其用作装饰器(从 2.6 开始;此示例来自文档):
import atexit
@atexit.register
def goodbye():
print "You are now leaving the Python sector."
If you wanted to make it specific to KeyboardInterruptonly, another person's answer to this question is probably better.
如果您只想使其特定于KeyboardInterrupt,另一个人对这个问题的回答可能更好。
But note that the atexitmodule is only ~70 lines of code and it would not be hard to create a similar version that treats exceptions differently, for example passing the exceptions as arguments to the callback functions. (The limitation of atexitthat would warrant a modified version: currently I can't conceive of a way for the exit-callback-functions to know about the exceptions; the atexithandler catches the exception, calls your callback(s), then re-raises that exception. But you could do this differently.)
但请注意,该atexit模块只有约 70 行代码,创建一个以不同方式处理异常的类似版本并不难,例如将异常作为参数传递给回调函数。(其限制atexit将保证修改版本:目前我无法设想退出回调函数了解异常的方法;atexit处理程序捕获异常,调用您的回调,然后重新引发那个例外。但你可以用不同的方式来做。)
For more info see:
有关更多信息,请参阅:
- Official documentation on
atexit - The Python Module of the Week post, a good intro
- 官方文档
atexit - 本周发布的Python 模块,一个很好的介绍
回答by Rohit Jain
I tried the suggested solutions by everyone, but I had to improvise code myself to actually make it work. Following is my improvised code:
我尝试了每个人建议的解决方案,但我必须自己即兴编写代码才能使其真正发挥作用。以下是我的即兴代码:
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

