14.10.4 什么情况下不调用atexit函数
如果满足以下任意一个条件,就不会调用为atexit注册的回调。
1.程序由于一个信号而终止。
2.直接调用了os._exit()。
3.检测到解释器中的一个致命错误。
可以更新subprocess一节中的例子,显示程序因为一个信号而终止时会发生什么。这里涉及两个文件,父程序和子程序。父程序启动子程序,暂停,然后中止子程序。
import os
import signal
import subprocess
import time
proc = subprocess.Popen('./atexit_signal_child.py',shell=True)
print('PARENT: Pausing before sending signal...')
time.sleep(1)
print('PARENT: Signaling child')
os.kill(proc.pid,signal.SIGTERM)
子程序建立一个atexit回调,然后休眠,直至信号到来。
import atexit
import time
import sys
def not_called():
print('CHILD: atexit handler should not have been called')
print('CHILD: Registering atexit handler')
sys.stdout.flush()
atexit.register(not_called)
print('CHILD: Pausing to wait for signal')
sys.stdout.flush()
time.sleep(5)
运行这个脚本时,会生成以下输出。
子程序不会打印嵌在not_called()中的消息。
通过使用os._exit(),程序就可以避免调用atexit回调。
import atexit
import os
def not_called():
print('This should not be called')
print('Registering')
atexit.register(not_called)
print('Registered')
print('Exiting...')
os._exit(0)
由于这个例子绕过了正常的退出路径,所以没有运行回调。另外,打印输出不会刷新,所以要提供-u选项运行这个示例来启用无缓冲的I/O。
为了确保运行回调,可以在要执行的语句外运行或者通过调用sys.exit()使程序中止。
import atexit
import sys
def all_done():
print('all_done()')
print('Registering')
atexit.register(all_done)
print('Registered')
print('Exiting...')
sys.exit()
这个例子调用了sys.exit(),所以会调用注册的回调。