Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Ctrl-C结束我的脚本,但它没有被键盘中断异常捕获_Python_Try Except_Keyboardinterrupt_Jpype - Fatal编程技术网

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

Python Ctrl-C结束我的脚本,但它没有被键盘中断异常捕获,python,try-except,keyboardinterrupt,jpype,Python,Try Except,Keyboardinterrupt,Jpype,我有一个Python脚本,其中包含一个大循环,读取文件并执行一些操作(我使用了几个包,如urllib2、httplib2或BeautifulSoup) 看起来是这样的: try: with open(fileName, 'r') as file : for i, line in enumerate(file): try: # a lot of code # ....

我有一个Python脚本,其中包含一个大循环,读取文件并执行一些操作(我使用了几个包,如urllib2、httplib2或BeautifulSoup)

看起来是这样的:

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,但我不知道这是否是我无法捕获键盘中断的原因):

回溯(最近一次呼叫最后一次):

文件“/home/darcot/code/Crawler/Crawler.py”,第294行,从文件获取文章
content=Extractor(Extractor='articlextractor',url=url).getText()
文件“/usr/local/lib/python2.7/site packages/boilerpipe/extract/_init__.py”,第36行,在_init中__
连接=urllib2.urlopen(请求)
文件“/usr/local/lib/python2.7/urllib2.py”,urlopen中的第126行
return\u opener.open(url、数据、超时)
文件“/usr/local/lib/python2.7/urllib2.py”,第391行,打开
响应=自身打开(请求,数据)
文件“/usr/local/lib/python2.7/urllib2.py”,第409行,打开
"开放",
文件“/usr/local/lib/python2.7/urllib2.py”,第369行,在调用链中
结果=func(*args)
文件“/usr/local/lib/python2.7/urllib2.py”,第1173行,在http\u open中
返回self.do_open(httplib.HTTPConnection,req)
文件“/usr/local/lib/python2.7/urllib2.py”,第1148行,打开
引发URL错误(err)
URL错误:

当脚本在try块之外时,您很可能正在发出CTRL-C,因此没有捕获信号。

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

您在评论中提到,您使用的是
boilerpipe
Python包。此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解释器没有机会抛出异常。当删除导入
锅炉管道
时,问题消失

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

gdb --args python boilerpipe_test.py
[...]
(gdb) run
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".
[New Thread 0x7fffef62b700 (LWP 3840)]
[New Thread 0x7fffef52a700 (LWP 3841)]
[New Thread 0x7fffef429700 (LWP 3842)]
[New Thread 0x7fffef328700 (LWP 3843)]
[New Thread 0x7fffed99a700 (LWP 3844)]
[New Thread 0x7fffed899700 (LWP 3845)]
[New Thread 0x7fffed798700 (LWP 3846)]
[New Thread 0x7fffed697700 (LWP 3847)]
[New Thread 0x7fffed596700 (LWP 3848)]
[New Thread 0x7fffed495700 (LWP 3849)]
[New Thread 0x7fffed394700 (LWP 3850)]
[New Thread 0x7fffed293700 (LWP 3851)]
[New Thread 0x7fffed192700 (LWP 3852)]
gdb
会话,不使用
boilerpipe
导入:

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
信号。即使导入了
boilerpipe
JPype
,信号处理程序也会被触发。这样,当用户点击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" 

你写的代码看起来很干净。我也尝试执行嵌套的Try-Catch。很好。也许罪魁祸首就在大量代码中<代码>注意:避免嵌套的TRY-CATCH。为什么要捕获键盘中断异常两次?您使用的是哪个python版本?2.7.8? 我在Python3.4中尝试了类似于您的示例的东西,效果非常好…@flammi88我捕获了两次,因为我不确定它是否会被“Exception,e”捕获。但是它不应该这样做,而且大的尝试应该足以捕获异常。我使用的是Python 2.7,你有任何回溯日志吗?我肯定我在程序处于循环中时点击了Ctrl-C(这不难知道)由于我的循环在一个try块中,所以它不是正确的答案。我认为这是唯一合理的答案,非常感谢!然而,我现在不得不面对一个棘手的问题,你知道如何找到解决办法吗?也许通过定义另一个组合键,可以让我打破循环并正确退出程序,而JPype不会奇怪地处理这个问题?请看我更新的答案是否可以帮助您。在不研究JPype代码的情况下,这是我知道的唯一解决方案。。。我希望这能对你有所帮助。这确实帮助了我,非常感谢你!这个变通方法工作得很好。
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"