当前位置: 首页 > news >正文

Python 之 __file__ 变量导致打包 exe 后路径输出不一致的问题

现象

做项目的时候,一直使用 os.path.dirname(os.path.abspath(__file__)) 来获取当前目录。然而,最近却遇到了一个路径相关的问题。直接运行 py 文件是正常的,但是打包成 exe 之后,却显示因为路径问题导致程序报错无法继续执行。

比如我有一段获取当前目录的脚本代码:

test.py

import os
import timedef get_current_dir():return os.path.dirname(os.path.abspath(__file__))if __name__ == '__main__':current_dir = get_current_dir()print(current_dir)  # E:\lky_project\tmp_project\test_projecttime.sleep(10)

正常用 Python 解释器执行的话输出 E:\lky_project\tmp_project\test_project,看起来没什么问题。

好,接下来,我用下面的命令对 test.py 打包,打包后将生成的 test.exe 移动到和 test.py 相同的目录下(确保执行目录一致)。

E:\lky_project\tmp_project\test_project> pyinstaller -F ./test.py

然后双击运行 test.exe,结果输出的目录却是下面这种(看起来是个临时目录)。

显然,这两个输出不是同一个目录,而我中间只是做了打包的操作,并没有对代码进行任何额外修改,但为什么输出的目录却不一样呢?

原因

我搜了一下 DeepSeek,其中的分析我还是比较认同的,所以就不多说了。分析的原因如下:

  • __file__ 变量通常是指当前执行脚本的路径。当直接运行脚本时,__file__ 会返回该脚本的文件名,然后通过 os.path.abspath 获取绝对路径,再取目录名,得到的就是脚本所在的目录路径。这应该是正确的。
  • 但是当打包成 exe 后,比如使用 PyInstaller,情况可能会不同。PyInstaller 打包后的 exe 文件会将脚本解压到一个临时目录中运行,这时候 __file__ 可能指向的是这个临时目录中的路径,而不是原来的脚本位置。这就会导致 current_dir 在打包后得到的是临时目录的路径,而不是用户期望的 exe 所在的目录。

解决

既然原因找到了,总得找个解决方案。

sys.frozen

其中一个解决方法,利用程序打包前和打包后 sys.frozen 环境变量的不同来进行区分,不同情况使用不同的目录获取方式。

import sys
import os
import timedef get_current_dir():if getattr(sys, 'frozen', False):# 打包后的情况,使用 sys.executable 的目录print("frozen")return os.path.dirname(sys.executable)else:# 打包前,正常脚本执行print("not frozen")return os.path.dirname(os.path.abspath(__file__))current_dir = get_current_dir()
print(current_dir)time.sleep(10)

os.getcwd()

再有就是使用 os.getcwd() 来获取当前目录。

import os
import timedef get_current_dir():return os.path.abspath(os.getcwd())current_dir = get_current_dir()
print(current_dir)time.sleep(10)

pathlib

或者使用 pathlib 的 absolute() 或 resolve() 方法也可以。

import time
import pathlibdef get_current_dir():# return pathlib.Path("./").resolve()return pathlib.Path("./").absolute()current_dir = get_current_dir()
print(current_dir)time.sleep(10)

http://www.xdnf.cn/news/72613.html

相关文章:

  • skyreels
  • 【Python网络爬虫开发】从基础到实战的完整指南
  • 婴幼儿托育服务与管理实训室的设备配置与功能优化
  • Kubernetes相关的名词解释Service(15)
  • 怎么安装python3.5-以及怎么在这个环境下安装包
  • 【机器学习-线性回归-1】深入理解线性回归:机器学习中的经典算法
  • 日语学习-日语知识点小记-构建基础-JLPT-N4阶段(8): - (1)复习一些语法(2)「~ています」
  • SpringCloud和SpringCloudAlibaba技术栈全面对比
  • js添加点击监控事件的方式
  • CCF CSP 第37次(2025.03)(1_数值积分_C++)
  • 网工实验——按照接口划分VLAN
  • 影楼精修-中性灰磨皮算法解析
  • redhat秘钥登入
  • 基础知识查缺补漏:RMSE和MSE
  • TOGAF 敏捷冲刺:15 天 Scrum 冲刺实践
  • CentOS7安装MySQL教程
  • 01-初识前端
  • 9.策略模式:思考与解读
  • [FPGA基础] FIFO篇
  • 上位机软件开发的关键技术与应用解析​
  • uCOS3实时操作系统(系统初始化和任务启动)
  • close和shutdown
  • el-select+vue-virtual-scroller解决数据量大卡顿问题
  • Python 爬虫如何获取淘宝商品的 SKU 详细信息
  • 用74HC595芯片就可做一个SPI组件
  • 【内容摘要】大模型内容摘要实战 会议摘要 提示词技巧
  • 【Spring】深入解析 Spring AOP 核心概念:切点、连接点、通知、切面、通知类型和使用 @PointCut 定义切点的方法
  • oracle rac时区问题导致远程查询时间不准
  • 从洗衣房到国学课堂:海信冰箱发起跨越千里的山区助学行动
  • 2024年TETCI SCI2区:增强差分进化麻雀搜索算法DSSADE,深度解析+性能实测