4

我做了很多 Project Euler 编码问题,Python 是我的首选语言。很多程序通常需要很长时间才能完成,所以我正在努力实现一些有助于提供有关程序状态的诊断信息的东西:当KeyboardInterrupt发生时,我希望能够打印程序运行了多长时间以及一些信息帮助我弄清楚可能还需要多长时间。

这个问题是——KeyboardInterrupt当你点击时Ctrl-C,我仍然在退出程序……我认为这与这段代码的结构有很大关系,或者希望在 Python 中我还没有找到一些东西.

KeyboardInterrupt我希望我的代码在被捕获后立即在同一行恢复。

这是此代码的示例:

     try:
         ...
         ...
         ... #I interrupt code here and hopefully keep going!
         ...
         ...
     except KeyboardInterrupt:
         ...
     finally:
         ...

我希望有人理解这样做的目的,并且可以帮助我找到一种方法来做到这一点,或者解决这种从正在运行的代码中调用中断的丑陋方式。

4

2 回答 2

5

通常,在 try 块中触发异常后,您永远无法将执行返回到特定代码段,因为异常可能发生在某个深处,并且具有许多其他状态,这些状态受其他线程中的其他副作用影响。虽然您的程序可能不是这种情况,但鉴于在 Python 中没有允许这样做的通用解决方案,您想要做的基本上是使用异常处理是不可能的。

但是,SIGINT信号的默认处理程序是抛出KeyboardInterrupt异常 - 如果您可以劫持它来做其他事情,您实际上可以实现这一点。这是一个简单的程序:

import signal
import pdb

def signal_handler(signal, frame):
    pdb.set_trace()

signal.signal(signal.SIGINT, signal_handler)

count = 0
while True:
    count += 1

处理程序现在只是一个在当前帧调用调试器的SIGINT函数,并且每当按下 Ctrl-C 时,调试器就会在代码所在的帧内的确切点处触发。您当然可以简单地向上检查值,如下所示:

$ python /tmp/script.py 
^C--Return--
> /tmp/script.py(5)signal_handler()->None
-> pdb.set_trace()
(Pdb) u
> /tmp/script.py(10)<module>()
-> while True:
(Pdb) pp count
13321869
(Pdb) c
^C--Return--
> /tmp/script.py(5)signal_handler()->None
-> pdb.set_trace()
(Pdb) quit
Traceback (most recent call last):
...
    if self.quitting: raise BdbQuit
bdb.BdbQuit

所以调试器在 ctrl-c 完成后被触发,然后我将up 步到循环正在运行的帧(在你的情况下,你的代码),然后c继续执行,再次杀死它并触发一个错误的退出(通过键入quit)终止程序。如果你合并了它,你基本上可以随时中断并在任何地方检查程序的值。

于 2016-06-28T04:39:36.523 回答
1

“是的,”哈利说。“在 。. . 在一分钟内。我会把这件事弄清楚。” 他指了指地上砸烂的碗。罗恩点点头,离开了。“修复,”哈利咕哝着,用魔杖指着那些破碎的碎片,它们飞回了一起,就像新的一样,但没有把海龟精华放回碗里。-哈利波特与凤凰社

一旦引发键盘中断,该信息就会丢失 - try/catch 允许程序恢复,但在此之前发生的事情将永远丢失[1]

幸运的是,键盘中断实际上是 c 级的信号- 如果您愿意,您可以单独拦截和处理它tracebackintrospect模块应该会有所帮助

对于简单的黑客攻击,这应该没问题,尽管我一般会谨慎使用它,基于信号文档的评论(依赖于实现):

我们仍然存在这样的问题,在某些实现中,由键盘生成的信号(例如 SIGINT)被传递给所有线程(例如 SGI),而在其他实现中(例如 Solaris),这些信号被传递给一个随机线程(一种中间可能性是将其交付给主线程——POSIX?)。目前,我们有一个适用于所有三种情况的工作实现——如果 getpid() 与主线程中的不同,则处理程序将忽略信号。XXX 这是一个黑客。


脚注

[1]好吧,不,不是。你可以使用足够的自省在 python 中做任何事情,但这是一个糟糕的想法,不符合我的报价。如果您真的想做一些可怕的事情,这些人已经为您完成了:https ://github.com/ajalt/fuckitpy

于 2016-06-28T04:41:46.880 回答