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()
总结就是:使用
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已经让我们可以直通知识海洋的入口了,一起努力学习吧,解锁自己潜藏的能力!
平时灌溉,才有期待,运气一来,花自盛开!
【特别声明】本公号转载、引用的所有文章、图片、音频、视频文件等资料的版权归版权所有人所有,转载目的在于传递、分享信息给更多人。如果所选内容的作者认为其作品不宜供大家浏览,或不应无偿使用,请及时与我联系,以便迅速采取适当措施,避免给双方造成不必要的损失。