atexit --- 退出处理器¶
atexit 模块定义了用于注册和取消注册 退出处理器 的函数:即在“退出时”自动执行的函数,也就是说,当程序正常终结(例如,sys.exit() 被调用或主模块执行结束)时或者更一般的情况,当 interpreter shutdown 时。
退出时,所有已注册的退出处理器都会按照其注册时的 相反 顺序被调用。 如果你注册了 A, B 和 C,则在解释器关闭时它们将按照 C, B, A 的顺序运行。 这样做的假设是较低层级的模块通常会在较高层级的模块之前被导入,因此必须在较晚的时候被清理。
如果在退出处理器执行期间引发了异常,将会打印回溯信息(除非引发的是 SystemExit )并且异常信息会被保存。 在所有退出处理器都运行完毕之后,所引发的最后一个异常会被重新引发。
In programs that use multiple interpreters, each interpreter has its own stack
of exit handlers, which are executed when the interpreter shuts down
(for example, with concurrent.interpreters.Interpreter.close() or the
C API Py_EndInterpreter()).
Registration functions in this module only affect the interpreter they are
called from.
备注: 当程序被未由 Python 处理的信号终止时、检测到 Python 内部致命错误时,或者调用了 os._exit() 时,退出处理器将不会被调用。
注意: 在清理函数内部注册或注销函数可能产生的影响是未定义的。
警告
在编写退出处理器时,特别是在 C API 扩展中,请记住在完成清理之后其他退出处理器仍可能运行任意 Python 代码。 此类代码应当成功或因异常而失败,而不是导致程序崩溃。
在 3.12 版本发生变更: 现在尝试在退出处理器中启动新线程或通过 os.fork() 派生新进程会导致 RuntimeError。 在此之前,这可能导致主 Python 运行时线程在释放线程状态的同时内部 threading 例程或新进程尝试使用该状态之间的竞争条件,进而可能导致程序崩溃而不是正常关闭。
在 3.7 版本发生变更: 当配合子解释器使用时,已注册函数仅作用于它们被注册的解释器。
- atexit.register(func, *args, **kwargs)¶
将 func 注册为退出处理器。 任何要传递给 func 的可选参数都必须作为参数传递给
register()。 可以多次注册相同的函数和参数。这个函数返回 func 对象,可以把它当作装饰器使用。
- atexit.unregister(func)¶
将 func 移出退出处理器列表。 如果 func 此前未被注册则
unregister()将静默地不做任何事。 如果 func 已被注册一次以上,则该函数每次在atexit调用栈中的出现都将被移除。 当取消注册时会在内部使用相等性比较 (==),因此函数引用不需要具有匹配的标识号。
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')
# 或者:
atexit.register(goodbye, adjective='nice', name='Donny')
作为 decorator 使用:
import atexit
@atexit.register
def goodbye():
print('You are now leaving the Python sector.')
只有在函数不需要任何参数调用时才能工作。