atexit — 退出处理器


atexit 模块定义了用于注册和取消注册清理函数的函数。 如此注册的函数会在解释器正常终止时自动执行。 atexit 会按注册顺序的相反顺序运行这些函数;如果注册了 ABC,则在解释器终止时,它们将按 CBA 的顺序运行。

注意: 当程序被 Python 未处理的信号终止、检测到 Python 致命内部错误或调用 os._exit() 时,不会调用通过此模块注册的函数。

注意: 在清理函数内部注册或取消注册函数的效果是未定义的。

在 3.7 版本中更改: 当与 C-API 子解释器一起使用时,注册的函数是它们注册的解释器本地的。

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

func 注册为在终止时执行的函数。 要传递给 func 的任何可选参数都必须作为 register() 的参数传递。 可以多次注册相同的函数和参数。

在程序正常终止时(例如,如果调用了 sys.exit() 或主模块的执行完成),所有注册的函数都将按后进先出的顺序调用。 假设较低级别的模块通常会在较高级别的模块之前导入,因此必须在稍后进行清理。

如果在退出处理程序的执行过程中引发异常,则会打印回溯(除非引发 SystemExit),并且会保存异常信息。 在所有退出处理程序都有机会运行后,将重新引发最后一个引发的异常。

此函数返回 func,这使得可以将其用作装饰器。

警告

从注册的函数启动新线程或调用 os.fork() 可能会导致主 Python 运行时线程释放线程状态与内部 threading 例程或新进程尝试使用该状态之间的竞争条件。 这可能导致崩溃,而不是干净的关闭。

在 3.12 版本中更改: 尝试在注册的函数中启动新线程或 os.fork() 新进程现在会导致 RuntimeError

atexit.unregister(func)

从在解释器关闭时运行的函数列表中删除 func。 如果 func 之前未注册,unregister() 会静默地执行任何操作。 如果 func 已多次注册,则 atexit 调用堆栈中的该函数的每次出现都将被删除。 在取消注册期间,内部使用相等比较 (==),因此函数引用不需要具有匹配的标识。

另请参阅

模块 readline

atexit 的有用示例,用于读取和写入 readline 历史文件。

atexit 示例

以下简单示例演示了模块如何在导入时从文件初始化计数器,并在程序终止时自动保存计数器的更新值,而无需依赖应用程序在终止时显式调用此模块。

try:
    with open('counterfile') as infile:
        _count = int(infile.read())
except FileNotFoundError:
    _count = 0

def incrcounter(n):
    global _count
    _count = _count + n

def savecounter():
    with open('counterfile', 'w') as outfile:
        outfile.write('%d' % _count)

import atexit

atexit.register(savecounter)

位置参数和关键字参数也可以传递给 register(),以便在调用注册函数时传递给该函数

def goodbye(name, adjective):
    print('Goodbye %s, it was %s to meet you.' % (name, adjective))

import atexit

atexit.register(goodbye, 'Donny', 'nice')
# or:
atexit.register(goodbye, adjective='nice', name='Donny')

用作 装饰器

import atexit

@atexit.register
def goodbye():
    print('You are now leaving the Python sector.')

这仅适用于可以不带参数调用的函数。