最可靠的方式是检查 getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):打包时 sys.frozen 为 True 且 _MEIPASS 存在,开发时两者均不满足,可准确区分环境并获取正确路径。

可以通过检查 sys.frozen 属性是否存在且为 True 来判断当前是否运行在 PyInstaller 打包的可执行文件中。
检查 sys.frozen 是否为 True
PyInstaller 在打包后会将 sys.frozen 设置为 True,这是最直接、最可靠的检测方式:
- 在普通 Python 解释器中运行时,
sys.frozen属性不存在(访问会抛出AttributeError) - 在 PyInstaller 打包的程序中,
sys.frozen == True - 推荐写法(安全兼容):
import sys is_pyinstaller = getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS')
其中 _MEIPASS 是 PyInstaller 运行时解压资源的临时路径,与 frozen 一起使用可进一步确认环境,避免误判(例如某些其他打包工具也可能设置 frozen)。
获取可执行文件所在目录(区别于脚本路径)
打包后,__file__ 指向的是临时解压路径中的 .pyc 文件,不再反映原始位置。应使用:
-
sys._MEIPASS:PyInstaller 解压资源的绝对路径(仅在 frozen 状态下存在) - 常规获取“程序根目录”的推荐方式:
import sys import osdef get_root_path(): if getattr(sys, 'frozen', False):
打包后:可执行文件所在目录
return sys._MEIPASS else: # 开发时:.py 文件所在目录 return os.path.dirname(os.path.abspath(__file__))root = get_root_path()
区分开发与发布环境的典型用途
该检测常用于以下场景:
- 动态加载资源(如图片、配置文件):路径需根据是否打包切换
- 日志路径、缓存目录等写入位置适配(避免写入只读的
_MEIPASS) - 调试开关:开发时启用详细日志或 GUI 调试窗口,发布时关闭
- 禁用某些仅开发需要的依赖(如
watchdog、auto-py-to-exe)
注意事项
不要依赖以下方式判断:
-
sys.executable名称(Windows 上可能为 python.exe 或 exe,但名称不固定,且可被重命名) -
__file__是否含.exe(打包后它通常指向.pyc,不是 exe) - 仅检查
hasattr(sys, '_MEIPASS')(某些旧版或非标准打包行为可能缺失)
稳妥做法始终是组合判断:getattr(sys, 'frozen', False) + hasattr(sys, '_MEIPASS')。










