[英]Capture keyboardinterrupt in Python without try-except
Is there some way in Python to capture KeyboardInterrupt
event without putting all the code inside a try
- except
statement? Python 中是否有某种方法可以在不将所有代码放入
try
- except
语句中的情况下捕获KeyboardInterrupt
事件?
I want to cleanly exit without trace if user presses Ctrl + C .如果用户按下Ctrl + C ,我想干净地退出而不留痕迹。
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()
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 不那么烦人)
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
- except
block 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.这也允许您仅在代码的某些部分忽略中断,而不必每次都再次设置和重置信号处理程序。
I know this is an old question but I came here first and then discovered the atexit
module.我知道这是一个老问题,但我首先来到这里,然后发现了
atexit
模块。 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- KeyboardInterrupt
cleanup on Linux.我不知道它的跨平台跟踪记录或完整的警告列表,但到目前为止,它正是我在 Linux 上尝试处理
KeyboardInterrupt
中断后清理时所寻找的。 Just wanted to throw in another way of approaching the problem.只是想以另一种方式解决问题。
I want to do post-exit clean-up in the context of Fabric operations, so wrapping everything in try
/ except
wasn't an option for me either.我想在 Fabric 操作的上下文中进行退出后清理,因此将所有内容都包含在
try
/ except
中也不是我的选择。 I feel like atexit
may be a good fit in such a situation, where your code is not at the top level of control flow.我觉得
atexit
可能非常适合这种情况,即您的代码不在控制流的顶层。
atexit
is 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 KeyboardInterrupt
only, another person's answer to this question is probably better.如果您只想使其特定于
KeyboardInterrupt
,那么另一个人对这个问题的回答可能会更好。
But note that the atexit
module 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.但请注意,
atexit
模块只有约 70 行代码,创建一个类似的版本以不同方式处理异常并不难,例如将异常作为参数传递给回调函数。 (The limitation of atexit
that would warrant a modified version: currently I can't conceive of a way for the exit-callback-functions to know about the exceptions; the atexit
handler catches the exception, calls your callback(s), then re-raises that exception. But you could do this differently.) (需要修改版本的
atexit
的限制:目前我无法设想退出回调函数了解异常的方法; atexit
处理程序捕获异常,调用您的回调,然后重新- 引发该异常。但您可以以不同的方式执行此操作。)
For more info see:有关更多信息,请参阅:
atexit
atexit
官方文档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
.您可以通过替换
sys.excepthook
来防止为KeyboardInterrupt
打印堆栈跟踪,而无需try: ... except KeyboardInterrupt: pass
(最明显且可能是“最佳”的解决方案,但您已经知道它并要求其他东西)。 Something like就像是
def custom_excepthook(type, value, traceback):
if type is KeyboardInterrupt:
return # do nothing
else:
sys.__excepthook__(type, value, traceback)
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
If someone is in search for a quick minimal solution,如果有人正在寻找快速的最小解决方案,
import signal
# The code which crashes program on interruption
signal.signal(signal.SIGINT, call_this_function_if_interrupted)
# The code skipped if interrupted
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.