如何检测当前运行环境是否为 PyInstaller 打包的可执行文件

最可靠的方式是检查 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 os

def 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 调试窗口,发布时关闭
  • 禁用某些仅开发需要的依赖(如 watchdogauto-py-to-exe

注意事项

不要依赖以下方式判断:

  • sys.executable 名称(Windows 上可能为 python.exe 或 exe,但名称不固定,且可被重命名)
  • __file__ 是否含 .exe(打包后它通常指向 .pyc,不是 exe)
  • 仅检查 hasattr(sys, '_MEIPASS')(某些旧版或非标准打包行为可能缺失)

稳妥做法始终是组合判断:getattr(sys, 'frozen', False) + hasattr(sys, '_MEIPASS')