Python如何实现程序结束时无条件执行函数?PyInstaller打包exe后失效怎么解决?
PyInstaller打包后程序关闭触发清理逻辑的通用解决方案
现有实现失效的核心原因有三个:
- 仅绑定了
SIGINT信号(仅对应Ctrl+C终止场景),未覆盖Windows下点击窗口右上角关闭触发的SIGBREAK信号,以及进程被系统正常结束触发的SIGTERM等信号- 信号处理函数要求接收
signum和frame两个入参,你当前直接将无入参的end_event绑定为信号处理函数,触发时会因参数不匹配抛出异常,无法正常执行- PyInstaller打包后的程序(尤其是添加
--windowed参数的无控制台版本),默认不会传递部分系统终止信号到Python层,atexit仅在Python解释器正常退出时触发,被系统强制终止时不会执行
- 首先修改
end_event兼容信号处理的入参要求,移除函数内的exit(1)调用:atexit触发时已经处于程序退出流程,重复调用exit会导致逻辑中断 - 补全所有终止信号的绑定,覆盖不同操作系统、不同终止方式的场景
- 如果打包时使用了
--windowed参数(无黑框的窗口程序),额外添加Windows API的控制台关闭事件监听
修改后的完整可运行代码如下:
import atexit import signal import pyupbit import sys # 此处替换为你自己的buy_list、upbit初始化逻辑 buy_list = {} upbit = pyupbit.Upbit("你的access_key", "你的secret_key") def end_event(signum=None, frame=None): for keys in buy_list.keys(): order = upbit.get_order(keys) if "state" in order: if(order['state'] == 'wait'): upbit.cancel_order(keys) # 注册atexit触发逻辑,覆盖Python解释器正常退出场景 atexit.register(end_event) # 绑定所有常见终止信号 signal_map = { signal.SIGINT: end_event, signal.SIGTERM: end_event, } # Windows系统下额外绑定SIGBREAK信号(对应窗口关闭操作) if sys.platform == "win32": signal_map[signal.SIGBREAK] = end_event for sig, handler in signal_map.items(): try: signal.signal(sig, handler) except: pass # PyInstaller打包后的运行环境额外处理Windows关闭事件 if getattr(sys, 'frozen', False): if sys.platform == "win32": import ctypes def win_ctrl_handler(ctrl_type): # 0=Ctrl+C触发、2=窗口关闭按钮触发 if ctrl_type in (0, 2): end_event() return True return False ctypes.windll.kernel32.SetConsoleCtrlHandler( ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_uint)(win_ctrl_handler), True ) # 以下为你的业务逻辑代码 # ...
打包注意事项
- 打包时如果用到ctypes相关逻辑,可添加
--collect-submodules ctypes参数避免依赖缺失 - 系统级的强制终止(比如任务管理器选择结束进程、执行
kill -9命令)会直接杀死进程,不会触发任何用户态清理逻辑,该场景没有通用解决方案
内容的提问来源于stack exchange,提问作者JustTemp
相关产品推荐
相关产品推荐

