在Python中,是否有可能在调用之后但在其后面的try块“之前”发生异常?

use*_*953 2 python multithreading signals exception keyboardinterrupt

给定一个函数调用和紧随其后的 try 块,是否存在调用正常返回但引发异常且 try 块未捕获的情况?

例如:

# example 1
resource = acquire_a_resource()
try:
    resource.do_something()
    # some more code...
finally:
    resource.close()
Run Code Online (Sandbox Code Playgroud)

有没有可能acquire_a_resource()正常返回但resource.close()不会被调用?

或者换句话说,是否存在以下场景:

# example 2
resource = None
try:
    resource = acquire_a_resource()
    resource.do_something()
    # some more code...
finally:
    if resource:
        resource.close()
Run Code Online (Sandbox Code Playgroud)

会比示例 1 更安全吗?

KeyboardInterrupt也许是因为与/线程/信号有关?

tor*_*rek 5

是的,至少在理论上是这样,尽管在 CPython 中不是这样(详细信息请参阅脚注)。线程并不是特别相关,但您的 KeyboardInterrupt 场景恰到好处:

\n\n
resource = acquire_a_resource()\n
Run Code Online (Sandbox Code Playgroud)\n\n

调用该函数。该函数获取资源并返回句柄,然后在给变量赋值期间,1发生键盘中断。所以:

\n\n
try:\n
Run Code Online (Sandbox Code Playgroud)\n\n

不运行\xe2\x80\x94 KeyboardInterrupt,而是发生异常,离开当前函数并取消绑定变量。

\n\n

第二个版本通过该finally子句,因此假设if resource找到它 boolean-truth-y,resource.close()确实会被调用。

\n\n

time.sleep(1)(请注意,实际触发此操作通常非常困难:您必须恰到好处地计时中断。您可以通过例如在 之前添加 来大幅增加竞争窗口try。)

\n\n

在许多情况下,with语句效果很好:

\n\n
with acquire_a_resource() as resource:\n    resource.do_something()\n
Run Code Online (Sandbox Code Playgroud)\n\n

其中close内置于__exit__方法中。即使该块通过异常转义,该方法也会运行。

\n\n
\n\n

1一般来说,实现有义务完成获取的资源到变量的绑定,否则会出现不可恢复的竞争。在 CPython 中,会发生这种情况,因为解释器会检查语句之间的中断,有时还会检查源代码中的重要位置。

\n\n

CPython 实际上添加了另一个特殊情况:

\n\n
resource = acquire_a_resource()\n
Run Code Online (Sandbox Code Playgroud)\n\n

Python/ceval.c,接近 1000 线)。

\n\n

所以实际上这条try线确实运行,因为这里有SETUP_FINALLY。我根本不清楚其他 Python 实现是否也做同样的事情。

\n