Python中的KeyboardInterrupt是什么时候被触发的?

10

所有文档告诉我们的是:

当用户按下中断键(通常为Control-CDelete)时引发。在执行过程中,会定期检查是否有中断。

但是从代码角度来看,我什么时候能看到这个异常呢?它是在语句执行期间发生的吗?只在语句之间发生?它可以发生在表达式的中间吗?

例如:

file_ = open('foo')
# <-- can a KeyboardInterrupt be raised here, after the successful
# completion of open but prior to the try? -->
try:
    # try some things with file_
finally:
    # cleanup

这段代码在一个恰当的KeyboardInterrupt时会泄露吗?还是在执行某些语句或表达式时引发它?

2个回答

6
根据PEP 343中的一条注释:
即使您编写了无错误的代码,KeyboardInterrupt异常仍可能导致它在任何两个虚拟机操作码之间退出。因此,它可以发生在任何地方。它确实可以在单个表达式的评估过程中发生。(这并不奇怪,因为表达式可以包括函数调用,并且在函数调用中几乎可以发生任何事情。)

3

是的,在你标记的地方可能会发生KeyboardInterrupt

为了处理这种情况,你应该使用with块:

with open('foo') as file_:
    # do some things
    raise KeyboardInterrupt

# file resource is closed no matter what, even if a KeyboardInterrupt is raised

然而,在调用open()和将文件分配给file_之间,异常可能会发生。这个问题可能不值得担心,因为通常情况下,按下ctrl-c意味着您的程序即将结束,所以"泄漏"的文件句柄将被操作系统清理。但如果您知道这很重要,可以使用信号处理程序来捕获触发KeyboardInterrupt(SIGINT)的信号。


不幸的是,with 并不总是可行的;有时您想要在调用 __enter__ 之前查看 with 语句中的表达式是否失败(例如,它是否引发了特定的异常?)。您无法使用 with 来实现此目的,因为这会使您失去包装表达式而不包装 with 体的能力。(如果 with 体可以引发与 with 表达式相同类型的异常,则意味着您无法在 except 中区分它们。) - Thanatos

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