finally 与 atexit 的区别

1 投票
3 回答
2189 浏览
提问于 2025-04-17 15:50

我最终需要写一些简单的 Python 包装脚本,结构大致是这样的:

try:
    code
    ...
    ...
except:
    raise
finally:
    file_handle.close()
    db_conn.close()

注意,在 except 块中,我所做的就是把错误信息重新抛给调用这个脚本的地方,没有任何额外的处理;在我的具体情况下,这样做没有问题。这里的想法是,无论有没有错误,清理代码都应该通过 finally 块来执行。

我是不是可以用 atexit 处理器来实现这个目的?这样的话,我就可以省去 try 带来的额外缩进层级。

3 个回答

1

atexit 是在程序结束时被调用的,所以这不是你想要的东西。

4

atexit模块提供了一个简单的方法,可以注册一些函数,让它们在程序正常关闭时被调用。注册的函数会在解释器正常结束时自动执行。

import atexit

def cleanup():
    print 'performimg cleanup'

# multiple functions can be registered here...    
atexit.register(cleanup)

另外,sys模块也有一个功能,叫做sys.exitfunc,但这里只能注册一个函数。

finally通常和try except一起使用,它的功能也可以用来做一些类似清理的工作,不过在finally块里,sys.exc_info的值都是None。

如果finally部分抛出了另一个异常,之前保存的异常会被丢弃。不过你可以在用atexit注册的函数里加上try except来处理这些异常。

另一个优缺点是,atexit注册的函数只会在程序结束时执行,而finally(配合try-except)可以在代码的任何地方使用,进行清理工作。

在你的场景中,如果你想在清理内容中抛出异常,使用atexit会很有帮助,前提是你可以接受清理工作在程序结束时进行。

1

只需使用 contextlib.closing

with closing(resource1) as f1, closing(resource2) as f2:
    f1.something()
    f2.something()

这样它们会自动关闭。文件对象可以直接作为上下文使用,所以你不需要调用 closing

如果你的资源不仅仅使用 close 方法,你可以使用 contextlib.contextmanager 装饰器来创建自定义函数。

撰写回答