Python中的atexit

atexit是标准库中一个简单的小模块,作用是提供退出的回调。 如果有什么事是在退出时需要做的,就可以使用它。 但仅限于比较简单的程序。 实际上,最好不要使用它。

由来

atexit其实由来已久,属于上个世纪的设计。 它不仅是Python标准库的一部分,其实最初是Unix系统的一个机制,在C、C++中也存在。 在现在的Linux、Mac OS X上,通过man atexit,都可以看到一个帮助页面。 这里有一个Linux man atexit的在线版。

Python里atexit,和Unix系统是同一个机制。 在程序的任何地方都可以注册一个或多个回调函数,在程序退出时执行。

需要注意的是,虽然无论是正常退出、还是异常退出(返回值非0),这个机制都会被触发; 但是,在被杀掉时——比如Ctrl+c,或kill -9等场景,是被外部信号(signal)控制退出——都是不会生效的。

官方文档

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

Register func as a function to be executed at termination. Any optional arguments that are to be passed to func must be passed as arguments to register(). It is possible to register the same function and arguments more than once.

At normal program termination (for instance, if sys.exit() is called or the main module’s execution completes), all functions registered are called in last in, first out order. The assumption is that lower level modules will normally be imported before higher level modules and thus must be cleaned up later.

If an exception is raised during execution of the exit handlers, a traceback is printed (unless SystemExit is raised) and the exception information is saved. After all exit handlers have had a chance to run the last exception to be raised is re-raised.

This function returns func, which makes it possible to use it as a decorator.

def atexit.unregister(func)

Remove func from the list of functions to be run at interpreter shutdown. After calling unregister(), func is guaranteed not to be called when the interpreter shuts down, even if it was registered more than once. unregister() silently does nothing if func was not previously registered.


其实就是注册、注销两个简单的操作。

注意

样例

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

"""
Play with atexit
"""

import atexit
import sys

print('enter script')

# do something
print('do something')

def _leave_0():
    print('exit script 0')


def _leave_1(*args):
    print('args:', args)
    print('exit script 1')


atexit.register(_leave_0)
atexit.register(_leave_1, *sys.argv)

if len(sys.argv) < 2:
    atexit.unregister(_leave_1)

将以上文件命名为play_atexit.py,执行可得以下结果。

$ python3 play_atexit.py
enter script
do something
exit script 0
$ python3 play_atexit.py 1 2 3
enter script
do something
args: ('play_atexit.py', '1', '2', '3')
exit script 1
exit script 0

总结

从样例中,可以看出以下特点。

虽然atexit简单方便,但是在简单的脚本中,做好流程控制,并不需要使用它。 只有比较复杂的程序,比如sys.exit()操作不在当前层级,而又需要当前层级作出处理时,才需要会用到吧。 如果在多个层级滥用,会导致流程失控,发生一些难以debug的情况。

因此,最终还是建议禁用atexit


相关笔记