gpt4 book ai didi

python - 无法在命令提示符下两次捕获KeyboardInterrupt?

转载 作者:太空狗 更新时间:2023-10-29 17:20:20 24 4
gpt4 key购买 nike

今天,当我发现有些奇怪的东西时,我不得不检查我的脚本如何在Windows命令提示符[1]上运行。我正在从事与此类似的工作,但这足以证明问题所在。这是代码。

def bing():
try:
raw_input()
except KeyboardInterrupt:
print 'This is what actually happened here!'

try: # pardon me for those weird strings
bing() # as it's consistent with everything in the chat room (see below)
print 'Yoo hoo...'
except KeyboardInterrupt:
print 'Nothing happens here too!'
这是情况。当脚本运行时,它将等待输入,并且用户应按Ctrl + C组合键以生成 KeyboardInterrupt,该 except将(应该)被 bing()中的 KeyboardInterrupt块捕获。因此,这应该是实际输出。而且,这就是我在Ubuntu终端和IDLE(在Windows和Ubuntu上)上运行它时发生的情况。
This is what actually happened here!
Yoo hoo...
但是,这并没有在Windows命令提示符下按预期进行。我宁愿得到一个奇怪的输出。
This is what actually happened here! Nothing happens here too!
看起来像一个 signal.signal在整个程序中传播并最终终止了它。
我尽力了。首先,我使用 SIGINT来处理 Exception(这不起作用),然后使用处理函数来产生一个 try... catch,稍后再捕获(这也不起作用),然后事情变得比它曾经是。因此,我回到了原来的 EOFError。然后,我去了Python专家室。
@poke suggested,当我们按Ctrl + C时会引发 EOFError。然后,在按Ctrl + Z并按Enter时, @ZeroPiraeus said会升起。
这很有帮助,这驱动了 discussion after a few minutes of fiddling around。很快,一切都变得困惑了!一些结果很好,一些结果出乎意料,还有一些 went haywire!

结论是停止使用Windows,并要求我的 friend 使用终端机(我同意)。但是我可以通过捕获 EOFErrorKeyboardInterrupt来解决。虽然每次按Ctrl + Z和Enter感到很懒,但这对我来说不是一个大问题。但是,这对我来说是一种困扰。
在进一步的研究中,我还注意到当按Ctrl + C时CMD上没有 KeyboardInterrupt出现。

底部没有任何内容。那么,这里发生了什么呢?为什么 KeyboardInterrupt传播?有没有办法使输出与终端一致?

[1]:我一直在终端上工作,但是今天我需要确保我的脚本可以在所有平台上运行(尤其是因为我的大多数 friend 都是非编码者,只是坚持使用Windows)。

最佳答案

链接user2357112的问题以某种方式对此进行了解释:Why can't I handle a KeyboardInterrupt in python?

键盘中断是异步引发的,因此它不会立即终止应用程序。取而代之的是,Ctrl + C在某种事件循环中进行处理,该过程需要一段时间才能到达那里。不幸的是,在这种情况下,您不能可靠地捕获KeyboardInterrupt。但是我们可以做一些事情来达到目标​​。

正如我昨天所解释的,停止raw_input调用的异常不是KeyboardInterrupt而是EOFError。您可以通过如下更改bing函数轻松地验证这一点:

def bing():
try:
raw_input()
except Exception as e:
print(type(e))

您会看到打印的异常类型是 EOFError而不是 KeyboardInterrupt。您还将看到 print甚至没有完全通过:没有新行。这显然是因为输出被print语句将异常类型写入stdout之后立即到达的中断所中断。当您向打印物中添加更多内容时,也可以看到以下内容:
def bing():
try:
raw_input()
except EOFError as e:
print 'Exception raised:', 'EOF Error'

请注意,我在这里为print语句使用了两个单独的参数。执行此操作时,我们可以看到“引发异常”文本,但不会出现“EOF错误”。相反,外部调用的 except将触发,并捕获键盘中断。

不过,在Python 3中事情变得更加失控。采取以下代码:
def bing():
try:
input()
except Exception as e:
print('Exception raised:', type(e))

try:
bing()
print('After bing')
except KeyboardInterrupt:
print('Final KeyboardInterrupt')

这几乎就是我们之前所做的,只是对Python 3语法进行了修改。如果运行此命令,则会得到以下输出:
Exception raised: <class 'EOFError'>
After bing
Final KeyboardInterrupt

因此我们可以再次看到EOFError被正确捕获,但是由于某种原因,Python 3的执行比此处的Python 2继续执行的时间长得多,因为 bing()之后的打印也被执行了。更糟糕的是,在使用cmd.exe的某些执行中,我得到的结果是根本没有捕获到键盘中断(显然,该中断在程序已经完成之后得到了处理)。

那么,如果要确保得到键盘中断,我们该怎么办?我们肯定知道的一件事是,打断 input()(或 raw_input())提示总是会产生 EOFError:这是我们一直以来所见的一致现象。因此,我们所能做的就是捕捉到该错误,然后确保获得键盘中断。

一种方法是从 KeyboardInterrupt的异常处理程序中引发 EOFError。但这不仅让人感到肮脏,而且还不能保证实际上中断实际上是终止输入提示的原因(谁知道还有什么可能引发EOFError?)。所以我们应该让已经存在的中断信号产生异常。

我们这样做的方法非常简单:我们等待。到目前为止,我们的问题是执行继续进行,因为异常没有足够快地到达。那么,如果我们稍等一下让异常最终到达,然后再继续其他事情,该怎么办呢?
import time
def bing():
try:
input() # or raw_input() for Python 2
except EOFError:
time.sleep(1)

try:
bing()
print('After bing')
except KeyboardInterrupt:
print('Final KeyboardInterrupt')

现在,我们只捕获EOFError并稍等片刻,以使后面的异步进程稳定下来并决定是否中断执行。这始终使我能够在外部try/catch中捕获 KeyboardInterrupt,并且除了我在异常处理程序中所做的操作之外,将不会打印其他任何内容。

您可能会担心一秒钟的等待时间很长,但是在我们这种情况下,如果我们中断执行,那一秒钟永远不会持续很长时间。在 time.sleep之后仅几毫秒的时间,捕获了中断,我们就在异常处理程序中。因此,一秒钟只是故障保护,它将等待足够长的时间,以确保异常能够及时到达。在最坏的情况下,当实际上没有中断而只有“正常” EOFError时?然后,以前无限阻塞以供用户输入的程序将花费一秒钟更长的时间才能继续;从来都不是真正的问题(更不用说EOFError可能非常罕见)。

因此,我们有了解决方案:仅捕获EOFError,然后稍等片刻。至少我希望这是一个可以在我自己的^ _ ^以外的其他机器上使用的解决方案。昨晚之后,我对此不太确定,但是至少我在所有终端和不同的Python版本上都有一致的经验。

关于python - 无法在命令提示符下两次捕获KeyboardInterrupt?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31127652/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com