CtrlC结束我的脚本,但它没有被键盘中断异常捕获

2024-06-13 12:53:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个python脚本,它包含一个大循环,读取一个文件并执行一些操作(我使用了几个包,比如urllib2、httplib2或beauthoulsoup)。在

看起来像这样:

try:
    with open(fileName, 'r') as file :
        for i, line in enumerate(file):
            try:
                # a lot of code
                # ....
                # ....
            except urllib2.HTTPError:
                print "\n >>> HTTPError"
            # a lot of other exceptions
            # ....
            except (keyboardInterrupt, SystemExit):
                print "Process manually stopped"
                raise
            except Exception, e:
                print(repr(e))
except (KeyboardInterrupt, SystemExit):
    print "Process manually stopped"
    # some stuff

问题是程序在我按下Ctrl-C时停止,但是它没有被我的两个键盘中断异常捕捉到,尽管我确信它目前在循环中(因此至少在大try/except中)。在

怎么可能?一开始我以为这是因为我使用的一个包不能正确地处理异常(比如使用“except:”only),但如果是这样,我的脚本就不会停止。但剧本确实停了,至少应该有一个我的两个孩子抓住,不是吗?在

我哪里错了?在

提前谢谢!在

编辑:

在try-except后面添加了一个finally:子句,并在两个try-except块中打印回溯,当我点击Ctrl-C时,它通常会显示None,但我曾经设法得到这个(似乎它来自urllib2,但我不知道这是否是我无法捕获键盘中断的原因):

回溯(最近一次呼叫):

^{pr2}$

Tags: of脚本键盘urllib2processfilelotprint
2条回答

很可能是在脚本位于try块之外时发出CTRL-C,因此无法捕获信号。在

我已经在我对这个问题的评论中指出,这个问题很可能是由问题中遗漏的代码部分引起的。但是,确切的代码不应该相关,因为当Python代码被Ctrl-C中断时,Python通常会抛出一个KeyboardInterrupt异常

您在评论中提到使用boilerpipePython包。这个Python包使用JPype创建到Java的语言绑定。。。我可以用下面的Python程序重现您的问题:

from boilerpipe.extract import Extractor
import time

try:
  for i in range(10):
    time.sleep(1)

except KeyboardInterrupt:
  print "Keyboard Interrupt Exception"

如果用Ctrl-C中断该程序,则不会引发异常。程序似乎会立即终止,这样Python解释器就没有机会抛出异常。当boilerpipe的导入被删除时,问题就消失了。。。在

带有gdb的调试会话表明,如果导入boilerpipe,Python启动了大量线程:

^{pr2}$

没有boilerpipe导入的gdb会话:

gdb  args python boilerpipe_test.py
[...]
(gdb) r
Starting program: /home/fabian/Experimente/pykeyinterrupt/bin/python boilerpipe_test.py
warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".
^C
Program received signal SIGINT, Interrupt.
0x00007ffff7529533 in __select_nocancel () from /usr/lib/libc.so.6
(gdb) signal 2
Continuing with signal SIGINT.
Keyboard Interrupt Exception
[Inferior 1 (process 3904) exited normally 

所以我假设您的Ctrl-C信号在另一个线程中被处理,或者jpype做了其他一些奇怪的事情,破坏了对Ctrl-C的处理

编辑:作为一种可能的解决方法,您可以注册一个信号处理程序,该处理程序在您按Ctrl-C时接收到的SIGINT信号。即使导入了boilerpipeJPype,信号处理程序也会被激发。这样,当用户点击Ctrl-C时,您将得到通知,您将能够在程序的中心点处理该事件。如果希望在此处理程序中终止脚本,可以终止该脚本。否则,一旦信号处理程序函数返回,脚本将在中断的地方继续运行。参见以下示例:

from boilerpipe.extract import Extractor
import time
import signal
import sys

def interuppt_handler(signum, frame):
    print "Signal handler!!!"
    sys.exit(-2) #Terminate process here as catching the signal removes the close process behaviour of Ctrl-C

signal.signal(signal.SIGINT, interuppt_handler)

try:
    for i in range(10):
        time.sleep(1)
#    your_url = "http://www.zeit.de"
#    extractor = Extractor(extractor='ArticleExtractor', url=your_url)
except KeyboardInterrupt:
    print "Keyboard Interrupt Exception" 

相关问题 更多 >