Ste*_*ica 116 python exception-handling finally try-catch-finally
对于Python中任何可能的try-finally块,是否可以保证finally块总是被执行?
例如,假设我在一个except块中返回:
try:
1/0
except ZeroDivisionError:
return
finally:
print("Does this code run?")
Run Code Online (Sandbox Code Playgroud)
或许我重新提出一个Exception:
try:
1/0
except ZeroDivisionError:
raise
finally:
print("What about this code?")
Run Code Online (Sandbox Code Playgroud)
测试显示finally上面的例子确实执行了,但我想还有其他我没有想过的场景.
是否有任何情况下finally块无法在Python中执行?
use*_*ica 182
"保证"比任何finally应得的实施都强得多.保证的是,如果执行流出整个try- finally构造,它将通过finally这样做.不能保证的是执行将流出try- finally.
一finally中一台发电机或异步协同程序可能永远不会运行,如果对象根本不会执行到结束.有很多方法可能发生; 这是一个:
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.')
Run Code Online (Sandbox Code Playgroud)
请注意,此示例有点棘手:当生成器被垃圾收集时,Python会尝试finally通过抛出GeneratorExit异常来运行块,但是在这里我们捕获该异常然后yield再次,此时Python打印出警告("生成器忽略了GeneratorExit ")并放弃.有关详细信息,请参阅PEP 342(通过增强型发生器协同程序).
生成器或协同程序可能无法执行结束的其他方式包括对象是否只是从来没有GC(是的,这是可能的,即使在CPython中),或者如果是async with awaitin __aexit__,或者如果对象awaits或yields在finally块中.此列表并非详尽无遗.
os._exit将立即停止进程而不执行finally块.
os.fork可能导致finally块执行两次.除了您期望发生两次事情的正常问题之外,如果未正确同步对共享资源的访问,这可能会导致并发访问冲突(崩溃,停顿......).
因为multiprocessing在使用fork start方法(Unix上的默认方法)时使用fork-without-exec来创建工作进程,然后os._exit在工作人员的工作完成后调用worker,finally并且multiprocessing交互可能会有问题(例如).
finally块运行.kill -SIGKILL将阻止finally块运行.SIGTERM并且SIGHUP还会阻止finally块运行,除非你自己安装一个处理程序来控制关闭; 默认情况下,Python不处理SIGTERM或SIGHUP.finally可以防止清理完成.其中特别值得注意的情况是,如果用户点击控制-C 只是因为我们已经开始执行该finally块.Python将引发KeyboardInterrupt并跳过finally块内容的每一行.(KeyboardInterrupt-safe代码很难写).finally块将无法运行.该finally块不是交易系统; 它不提供原子性保证或任何类型的保证.其中一些例子可能看起来很明显,但很容易忘记这些事情可能发生并依赖finally太多.
wim*_*wim 67
是. 最后总是赢.
击败它的唯一方法是在finally:获得执行机会之前暂停执行(例如,使解释器崩溃,关闭计算机,永久挂起发生器).
我想还有其他一些我没有想过的场景.
以下是您可能没有想到的更多内容:
def foo():
# finally always wins
try:
return 1
finally:
return 2
def bar():
# even if he has to eat an unhandled exception, finally wins
try:
raise Exception('boom')
finally:
return 'no boom'
Run Code Online (Sandbox Code Playgroud)
根据您退出解释器的方式,有时您最终可以"取消",但不是这样:
>>> import sys
>>> try:
... sys.exit()
... finally:
... print('finally wins!')
...
finally wins!
$
Run Code Online (Sandbox Code Playgroud)
使用不稳定os._exit(在我看来,这属于"崩解翻译"):
>>> import os
>>> try:
... os._exit(1)
... finally:
... print('finally!')
...
$
Run Code Online (Sandbox Code Playgroud)
我目前正在运行此代码,以测试在宇宙热死之后是否仍将执行:
try:
while True:
sleep(1)
finally:
print('done')
Run Code Online (Sandbox Code Playgroud)
但是,我还在等待结果,请稍后再回来查看.
嗯,是的,不.
保证是Python总是会尝试执行finally块.如果从块返回或引发未捕获的异常,则在实际返回或引发异常之前执行finally块.
(你可以通过简单地运行问题中的代码来控制自己)
我可以想象唯一一个不会执行finally块的情况是Python解释器本身崩溃,例如在C代码内或因断电而崩溃.
| 归档时间: |
|
| 查看次数: |
17940 次 |
| 最近记录: |