在广泛的异常情况下没有引发或捕获 KeyboardInterrupt 异常

3

请有人向我解释以下。让我们看一下代码:

if __name__ == '__main__':
    try:
        while 1:
            x = 2+2
    except KeyboardInterrupt:
        print('yo')

如果我运行这个程序,等待一段时间,然后按下Ctrl+C,将会处理一个异常并打印消息yo
如果我们将代码更改为捕获一个广泛的异常,像这样:
if __name__ == '__main__':
    try:
        while 1:
            x = 2+2
    except Exception, e:
        print('yo')
        print(e)

运行它,等待一段时间,按下Ctrl+C,将不会捕获KeyboardInterrupt异常。

根据Python文档

Python默认安装了少量信号处理程序:SIGPIPE被忽略(因此管道和套接字上的写入错误可以报告为普通的Python异常),而SIGINT被转换为KeyboardInterrupt异常。所有这些都可以被覆盖。

那么,为什么在第二种情况下这个异常没有被捕获或者抛出呢?

1个回答

4
您不能通过捕获Exception来捕获KeyboardInterrupt,因为前者只继承自BaseException。您可以在文档中了解更多信息:

异常KeyboardInterrupt

当用户按下中断键(通常为Control-C或Delete)时引发。在执行期间,会定期检查是否有中断。 等待输入时键入的中断也会引发此异常,例如内置函数input()raw_input()此异常继承自BaseException,以免被意外捕获并防止解释器退出。(我强调)

这意味着您需要执行以下操作:
except BaseException, e:

但这被认为是一种不好的做法。更好的方法是像你的第一个例子中那样直接捕获KeyboardInterrupt本身。


1
+1,但值得注意的是捕获所有BaseExceptions比捕获所有Exceptions更糟糕... - mgilson
这是一个关于单独线程的问题,但我会在这里问。如果我想要对所有类型的程序终止(优雅关闭)进行后处理,唯一的方法就是为所有相应的信号添加处理程序吗? - Dmitry Belaventsev
@dizpers - 嗯,如果你想要捕获“所有”异常,那么捕获BaseException就可以了。我是说,如果你只想捕获KeyboardInterrupt,那就只捕获KeyboardInterrupt就好了。 :) - user2555451
如果你想捕获所有异常,只需使用裸的 except: - kindall
@kindall - 或者那个。:) 对我来说,列出至少“一些东西”是一种习惯。 - user2555451
不是所有的异常,而只有终止信号,如SIGINT、SIGTERM、SIGKILL等。 - Dmitry Belaventsev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接