“最终”是否总是在Python中执行? [英] Does 'finally' always execute in Python?

查看:130
本文介绍了“最终”是否总是在Python中执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于Python中任何可能的try-finally块,是否保证将始终执行 finally 块?

For any possible try-finally block in Python, is it guaranteed that the finally block will always be executed?

例如,假设我在除外块中返回:

For example, let’s say I return while in an except block:

try:
    1/0
except ZeroDivisionError:
    return
finally:
    print("Does this code run?")

或者也许我重新提出 Exception

try:
    1/0
except ZeroDivisionError:
    raise
finally:
    print("What about this code?")

测试表明最终确实针对上述示例执行了,但我想我还没有想到其他场景。

Testing shows that finally does get executed for the above examples, but I imagine there are other scenarios I haven't thought of.

是否有任何场景其中最终块可能无法在Python中执行?

Are there any scenarios in which a finally block can fail to execute in Python?

推荐答案

保证是一个比任何实现都强大得多的词最终值得。可以保证的是,如果执行从整个 try - finally 构造中流出,它将通过最终这样做。无法保证执行会从尝试-最终流出。

"Guaranteed" is a much stronger word than any implementation of finally deserves. What is guaranteed is that if execution flows out of the whole try-finally construct, it will pass through the finally to do so. What is not guaranteed is that execution will flow out of the try-finally.

  • A finally in a generator or async coroutine might never run, if the object never executes to conclusion. There are a lot of ways that could happen; here's one:

def gen(text):
    try:
        for line in text:
            try:
                yield int(line)
            except:
                # Ignore blank lines - but catch too much!
                pass
    finally:
        print('Doing important cleanup')

text = ['1', '', '2', '', '3']

if any(n > 1 for n in gen(text)):
    print('Found a number')

print('Oops, no cleanup.')

请注意,此示例有些棘手:当生成器被垃圾回收时,Python尝试通过抛出 GeneratorExit 异常来运行最终块,但是在这里,我们捕获了该异常,然后 yield 再次出现,此时Python打印警告(发电机忽略GeneratorExit)并放弃。有关详细信息,请参见 PEP 342(通过增强型生成器的协程)

Note that this example is a bit tricky: when the generator is garbage collected, Python attempts to run the finally block by throwing in a GeneratorExit exception, but here we catch that exception and then yield again, at which point Python prints a warning ("generator ignored GeneratorExit") and gives up. See PEP 342 (Coroutines via Enhanced Generators) for details.

生成器或协程可能无法执行结论的其他方式包括是否从未对对象进行过GC处理(是的,即使在CPython中也是可能的)或 __ aexit __ 中的 await 异步,或者如果对象<$ c $在最终块中c> await s或 yield s。

Other ways a generator or coroutine might not execute to conclusion include if the object is just never GC'ed (yes, that's possible, even in CPython), or if an async with awaits in __aexit__, or if the object awaits or yields in a finally block. This list is not intended to be exhaustive.

A <如果所有非守护线程先退出,则守护线程中的code>最终可能永远不会执行

A finally in a daemon thread might never execute if all non-daemon threads exit first.

os._exit 将立即停止该过程,而无需执行最终块。

os._exit will halt the process immediately without executing finally blocks.

os.fork 可能导致最终阻止执行两次 。如果您对两次共享资源的访问不是正确同步

由于 multiprocessing 在使用 fork 启动方法(Unix上的默认方法),然后调用 os._exit 在工作人员完成工作后,最终多处理交互可能会出现问题(示例)。

Since multiprocessing uses fork-without-exec to create worker processes when using the fork start method (the default on Unix), and then calls os._exit in the worker once the worker's job is done, finally and multiprocessing interaction can be problematic (example).

finally 块不是交易系统;它不提供原子性保证或任何种类的保证。这些示例中的一些可能看起来很明显,但是很容易忘记这种事情可能发生,并且最终依赖

The finally block is not a transaction system; it doesn't provide atomicity guarantees or anything of the sort. Some of these examples might seem obvious, but it's easy to forget such things can happen and rely on finally for too much.

这篇关于“最终”是否总是在Python中执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆