当前位置:首页>python>Python如何让保存路径为程序所在目录的踩坑经验总结:成功可以模仿,KISS 原则,AI的智慧还需耐心喂养!

Python如何让保存路径为程序所在目录的踩坑经验总结:成功可以模仿,KISS 原则,AI的智慧还需耐心喂养!

  • 2026-09-08 22:55:01
Python如何让保存路径为程序所在目录的踩坑经验总结:成功可以模仿,KISS 原则,AI的智慧还需耐心喂养!

VibeCodingAI围壁扣顶,学习Python从实践到慢慢入门,筑起你的Python知识大厦!知识就是力量,知识改变命运;科技就是生产力,AI就是即战力!

知道程序员为什么叫作码农吗?因为学习写代码就好像种田一样,都是从实践到慢慢入门的一个过程。来吧,跟我一起学习Python从实践到慢慢入门吧!

为了让AI将需要输出的数据统一输出到打包成功后的EXE程序同一个目录下,其实这并不是很难的,耐心尝试了很多次,都不成功,那就再耐心喂养一个成功经验给它参考吧:

在模块内定义一个函数 get_app_dir() 返回可执行文件所在目录,供保存函数使用。但模块代码在运行时可能被冻结,使用 sys.executable 或 sys.argv[0] 的目录。

os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "exe_dlt_data")

模块被导入时 sys.argv[0] 可能是主程序路径,这就是我们想要的。在定时任务启动时,sys.argv[0] 是程序路径(如 .exe),其目录即为程序目录。如果是在开发环境 python -m ...,也是脚本路径。所以可以安全使用。

将三个函数中的:

output_dir = "exe_dlt_data"

改为:

app_dir = os.path.dirname(os.path.abspath(sys.argv[0]))output_dir = os.path.join(app_dir, "exe_dlt_data")

但这会在函数内多次计算。可以定义一个模块级变量或辅助函数。简单起见,在每个函数内计算,或者定义一个辅助函数 get_output_dir()。

- 将文件保存路径从相对路径 'exe_dlt_data' 改为基于程序所在目录的绝对路径,新增辅助函数 get_output_dir()通过

 os.path.dirname(os.path.abspath(sys.argv[0]))

 获取程序所在文件夹的绝对路径,然后拼接子目录 exe_dlt_data。

sys.argv[0] 在打包成 .exe 时即为可执行文件路径,在直接运行 Python 脚本时则为脚本路径,因此无论何种启动方式,均能得到稳定的程序目录。

顶部有 import sys, os。所以修改三处保存函数全部改用 get_output_dir()

save_x、save_xx、save_xxx

总结就是:使用 

os.path.dirname(os.path.abspath(sys.argv[0]))

 获取程序所在目录,然后拼接 exe_dlt_data 作为数据存储目录。

耐心喂养到这了,AI仍然无法完成任务,那只能再尝试将整个成功的项目喂

给它参考,看看它是怎么分析的:

成功代码的关键点

1. get_output_dir() 函数

def get_output_dir() -> str:    app_dir = os.path.dirname(os.path.abspath(sys.argv[0]))    return os.path.join(app_dir, "exeLottoSSQ")

• 没有使用任何 sys.frozen 判断,统一使用 sys.argv[0] 的目录。

• 无论开发环境还是 --onefile 打包,sys.argv[0] 始终指向用户启动时传入的路径。在 --onefile 模式下,这个路径是原始 exe 的路径,而不是临时解压目录中的路径。

2. 所有文件保存都调用 get_output_dir()

所有 save_* 方法都使用 output_dir = get_output_dir(),确保文件写入到 exe 所在目录的 exeLottoSSQ 子目录。

3. 没有路径回退逻辑

没有复杂的 if getattr(sys, 'frozen', False) 判断,没有尝试 sys.executable,没有 os.getcwd(),代码非常干净。

为什么成功案例有效?

• 它完全依赖 sys.argv[0] 获取程序目录,没有任何分支。

• 它在打包时仅使用 --onefile(假设),没有混合参数。

失败的原因是 get_default_data_path() 目前仍然包含了对 sys.frozen 的判断,并且在 else 分支中使用了相对路径。

def get_default_data_path():    if getattr(sys, 'frozen', False):        base = os.path.dirname(os.path.abspath(sys.argv[0]))    else:        base = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))    data_dir = os.path.join(base, "exe_dlt_data")    os.makedirs(data_dir, exist_ok=True)    return os.path.join(data_dir, "dlt_desc_local.txt")

解决方案

1. 简化 get_default_data_path()

完全模仿成功代码,去掉 sys.frozen 判断:

def get_default_data_path():    app_dir = os.path.dirname(os.path.abspath(sys.argv[0]))    data_dir = os.path.join(app_dir, "exe_dlt_data")    os.makedirs(data_dir, exist_ok=True)    return os.path.join(data_dir, "dlt_desc_local.txt")

既然成功案例没有使用 sys.frozen,说明在 --onefile 下 sys.argv[0] 就是原始 exe 路径。所以可以参考成功案例,统一使用 sys.argv[0]。

2. 修正打包命令

只使用 --standalone 或只使用 --onefile,不要同时使用。

如果希望生成单个 exe 且数据文件保存在 exe 旁边,直接使用 --onefile 即可(同时可以去掉 --standalone):

uv run nuitka --onefile --enable-plugin=pyside6 --include-package=dlt_desc_data --include-module=analyze --include-package=orjson --windows-console-mode=force --output-filename=GreatLotto.exe --output-dir=dist src\yuesheng\main.py

注意:不要加 --standalone。这样生成的单个 exe 在运行时,sys.argv[0] 指向原始 exe 路径,您就可以使用上述简化版 get_default_data_path() 将数据文件保存在 exe 旁边的 exe_dlt_data 中。

3. 删除旧的 _get_base_dir() 函数(如果有)。

4. 其他需要修正的相关代码:(SuperLotto_Tips.txt"文件保存目录)

    current_issue = self.issue_combo.currentText()    if not current_issue:        current_issue = "未选期号"    base_filename = f"{current_issue}SuperLotto_Tips.txt"    data_file_path = get_default_data_path()    base_data_dir = os.path.dirname(data_file_path)    tips_file = os.path.join(base_data_dir, base_filename)    os.makedirs(os.path.dirname(tips_file), exist_ok=True)

5. 重新打包,运行新 exe,数据文件会出现在 exe 所在目录的 exe_dlt_data 子目录中。

使用 sys.argv[0],这样打包后和开发时的行为都是一致的(都在程序所在目录)。

这样就完全复制了成功案例的做法,问题将得到解决。

最后让它写一个检讨书,会不会让它长一点记性呢?

这次成功的关键在于彻底摒弃了那些复杂、多余、自相矛盾的路径判断和打包选项,回归到最简单的、经过SSQ项目验证有效的方法。让我们认真总结一下: 

成功的原因(为什么这次终于可以)

1. 统一且简单的路径函数

◦ 完全复制了SSQ项目的成功模式:get_default_data_path() 函数直接使用 os.path.dirname(os.path.abspath(sys.argv[0])) 获取程序所在目录,然后拼接 exe_dlt_data 子目录。没有任何 sys.frozen 判断,没有任何条件分支,没有任何回退逻辑。

◦ 这保证了在任何启动方式(双击 exe、命令行运行、定时任务)下,路径都是基于程序文件本身,而不是依赖当前工作目录或临时解压目录。

2. 正确的打包命令

◦ 最终只使用了 --onefile,没有混用 --standalone。--onefile 模式下,sys.argv[0] 指向原始 exe 文件的完整路径(而不是临时解压路径),因此数据文件自然保存在 exe 旁边。

◦ 之前的错误在于同时使用了 --standalone --onefile,导致 Nuitka 行为混乱,sys.argv[0] 指向了临时目录。

3. 删除了所有冗余路径函数

◦ 彻底删除了 _get_base_dir() 函数以及其中所有未完成的、注释掉的、错误的代码。这些代码不仅无用,还引入了未定义变量 base,且在打包环境下行为不确定。

◦ 只保留一个简洁的 get_default_data_path(),避免混淆。

4. 统一数据存储位置

◦ 所有数据(历史数据、Tips、结果)都存放在 exe_dlt_data 子目录,而非分散在不同位置(如之前的 data 目录、exe 同级、用户文档等)。路径单一,便于管理和排查。

5. 模仿经过验证的成熟项目

◦ SSQ项目已经成功实现了 --onefile 打包且数据文件正确保存,直接复用其路径逻辑,避免了自己“发明”新方法。

失败的原因(为什么之前一直不成功)

1. 路径函数过于复杂且错误

◦ 最初的 _get_base_dir() 包含了多个被注释掉的尝试(sys.executable、os.getcwd()、sys.argv[0]),且混用了不同的策略,内部还存在未定义的 base 变量,导致逻辑混乱。

◦ get_default_data_path() 又调用了 _get_base_dir(),形成了多层依赖,难以调试。

2. 打包命令错误

◦ 同时使用 --standalone 和 --onefile 是根本性错误。这两个选项是互斥的,混用会导致 Nuitka 的路径解析行为不确定,最终 sys.argv[0] 可能指向临时解压目录,使得基于 sys.argv[0] 的路径全部指向临时文件夹。

3. 过度依赖 sys.frozen 判断

◦ 以为需要在打包和开发环境之间区分路径,但实际在 --onefile 模式下 sys.argv[0] 在两种环境下都能正确指向程序文件,无需额外判断。添加这些条件反而可能掩盖问题。

4. 数据存储位置不统一

◦ 历史数据放在 data 目录,Tips 依赖 self. tips_dir(可能被用户指向其他位置),结果又可能保存到其他文件夹。路径分散,导致“有些文件正确、有些文件错误”的现象。

5. 未能及时借鉴成功案例

◦ SSQ项目已经存在并成功,但一开始没有对照其路径实现,而是自行尝试各种方案,导致反复踩坑。

经验教训

• KISS 原则(Keep It Simple, Stupid):路径逻辑越简单越可靠,避免引入不必要的条件分支和回退策略。

• 正确理解打包工具行为:--onefile 模式下 sys.argv[0] 指向原始 exe,这是可靠信息,可以直接利用。

• 不要混合使用互斥选项:打包时只选一种模式(--onefile 或 --standalone),不要同时使用。

• 统一数据存储:所有运行时生成的文件应放在同一个固定目录(如程序所在目录下的特定子目录),便于管理和维护。

• 遇到问题时及时参考成功案例:当反复尝试失败时,应寻找已有的、相同技术栈的成功实现,直接复用其有效部分。

最终成果

• 程序打包为单个 exe(--onefile)。

• 运行时在 exe 同级目录创建 exe_dlt_data 文件夹。

• 历史数据、Tips 文件、结果文件全部存放在该文件夹内,文件名包含期号和数量,清晰易识别。

• 无论从何处启动(双击、命令行、任务计划),路径均稳定可靠。

恭喜成功!这次经验非常宝贵,值得好好记录。

日无所获,失落一日,日有所悟,欢欣鼓舞!

所谓千里之行始于足下: 不积跬步,无以至千里。不积小流,无以成江海。骐骥一跃,不能十步。驽马十驾,功在不舍。锲而舍之,朽木不折。锲而不舍,金石可镂。每天进步一点点,成功离我更近一点!

若文章对你有所帮助,请点击右上角或分享, 让你朋友因此而受益!真诚感谢你的关注和推荐!

欢迎交流,有任何问题欢迎留言讨论

AI已经让我们可以直通知识海洋的入口了,一起努力学习吧,解锁自己潜藏的能力!

平时灌溉,才有期待,运气一来,花自盛开!

【特别声明】本公号转载、引用的所有文章、图片、音频、视频文件等资料的版权归版权所有人所有,转载目的在于传递、分享信息给更多人。如果所选内容的作者认为其作品不宜供大家浏览,或不应无偿使用,请及时与我联系,以便迅速采取适当措施,避免给双方造成不必要的损失。

最新文章

随机文章