atexit 是 Python 标准库中的一个模块,用于注册程序正常终止时要自动执行的清理函数(回调)。它常被用来释放资源、保存数据或打印结束信息,避免在代码中分散编写退出处理逻辑。

常见应用场景:

(1)资源释放

在程序退出前关闭文件、网络连接或数据库连接。

(2)保存运行状态

在退出前将运行结果或缓存写入磁盘,方便下次启动继续使用。

(3)记录日志

在程序结束时统一写入退出日志。

(4)模拟析构行为

类似于 C++ 的 atexit,可将“退出动作”集中注册管理。

◆ ◆

核心概念

1、注册函数(register)

使用 atexit.register(func, *args, **kwargs) 将函数及参数注册为退出时执行的回调。

2、执行顺序

注册的回调函数按后进先出(LIFO) 顺序执行,即最后注册的先执行。

3、触发条件

程序正常退出(脚本执行完毕,或调用 sys.exit())时触发。

异常未捕获导致退出时,回调仍会执行。

注意:调用 os._exit() 退出不会执行回调。

4、参数传递

可以在 register() 时为回调函数指定位置参数和关键字参数。

5、注销函数(unregister)

Python 3.9+ 提供 atexit.unregister(func) 可移除已注册的回调。

◆ ◆

基本用法

# test.py
import atexit

def goodbye():
    print("程序已结束,执行清理操作...")

atexit.register(goodbye)

print("程序正在运行...")

运行:

python test.py

结果:

程序正在运行...
程序已结束,执行清理操作...

◆ ◆

应用举例

例 1、保存运行数据

import atexit
import json

data = {"count": 0}

def save_data():
    with open("data.json", "w") as f:
        json.dump(data, f)
    print("数据已保存。")

atexit.register(save_data)

for i in range(5):
    data["count"] += 1
    print(f"当前计数:{data['count']}")

运行结果:

程序退出时,会自动调用 save_data() 将 data 保存到 data.json。

例 2、多个回调函数

import atexit

def cleanup():
    print("释放资源...")

def log_exit():
    print("写入退出日志...")

atexit.register(cleanup)
atexit.register(log_exit)  # 后注册的先执行

print("主程序结束。")

输出:

主程序结束。
写入退出日志...
释放资源...

说明:log_exit() 先执行,因为它后注册。

例 3、注册带参数的回调

import atexit

def goodbye(name, age=None):
    print(f"再见,{name}!年龄:{age}")

atexit.register(goodbye, "Alice", age=20)

print("程序运行中...")

输出:

程序运行中...
再见,Alice!年龄:20

例 4、注销回调(Python 3.9+)

import atexit

def task():
    print("清理任务执行")

atexit.register(task)
atexit.unregister(task)  # 注销

print("程序结束")

输出:

程序结束

回调已被移除,因此程序退出时不会执行 task()。

◆ ◆

常用函数速览

atexit.register(func, *args, **kwargs)

注册一个函数作为退出回调。

参数

func:退出时要调用的函数对象

*args / **kwargs:传递给函数的参数

返回:返回 func,便于装饰器用法

atexit.unregister(func)

移除已注册的回调函数(Python 3.9+)。

参数

func:已注册的函数对象

返回:无

◆ ◆

补充说明

1、与 finally 的区别

finally 块在代码执行到特定位置时立即执行;

atexit 注册的回调会在整个程序完全退出前统一执行。

2、与类析构方法的区别

__del__ 是对象销毁时调用,而 atexit 是程序退出时调用。

3、不执行的情况

调用 os._exit() 或发生某些致命错误(如段错误)会直接终止进程,不会执行回调。

4、调试建议

在注册的函数里避免抛出异常,否则可能中断后续回调执行。

回调函数应简短、可快速完成,以免阻塞程序退出过程。

点赞有美意,赞赏是鼓励