【python】Path.cwd()、sys.executable、sys.argv、Path(__file__) 在PyInstaller打包前后的区别
PyInstaller打包Python脚本时,sys.executable、sys.argv和Path(__file__)的行为会发生变化:sys.executable从指向Python解释器变为指向可执行文件本身;sys.argv[0]从脚本文件名变成可执行文件名;Path(__file__)会指向临时解压目录而非原路径。建议使用sys._MEIPASS获取资源路径,并注意调试时参数传递的变化。
文章目录
在使用
PyInstaller 将 Python 脚本打包为独立可执行文件时, Path.cwd()、 sys.executable、 sys.argv 和 Path(__file__) 的行为会发生变化。理解这些差异有助于避免路径相关问题。以下是具体分析:
Path.cwd()
打包前(直接运行 Python 脚本)
当直接通过 Python 解释器运行脚本(如 python script.py)时,Path.cwd()返回的是执行脚本时终端(或命令行)的当前工作目录。
这个路径由用户在终端中执行脚本时的位置决定,与脚本本身的存储位置无关。
假设脚本 script.py存储在 D:\project\src,但用户在终端中执行以下操作:
# 当前终端工作目录是 D:\project
cd D:\project
python src\script.py # 执行脚本
此时 Path.cwd()返回 D:\project(终端的当前目录),而非脚本所在的 src目录。
打包后(运行 PyInstaller 生成的可执行文件)
PyInstaller 会将脚本及其依赖打包为一个独立的可执行文件(如 script.exe)。此时 Path.cwd() 的行为取决于用户启动可执行文件的方式:
(1) 通过命令行显式启动
如果在终端中通过命令行启动可执行文件(如 .\dist\script.exe),则 Path.cwd() 返回终端的当前工作目录(与打包前的逻辑一致)。
示例:
可执行文件 script.exe 存储在 D:\dist,用户在终端中执行:
# 当前终端工作目录是 D:\test
cd D:\test
D:\dist\script.exe # 启动可执行文件
此时 Path.cwd() 返回 D:\test(终端的当前目录),而非 D:\dist(exe 文件所在目录)。
(2) 通过文件管理器双击启动
如果通过文件管理器(如 Windows 资源管理器)直接双击可执行文件启动,Path.cwd() 通常返回可执行文件所在的目录
(这是多数操作系统的默认行为)。
示例:
双击 D:\dist\script.exe,此时 Path.cwd() 返回 D:\dist(exe 文件所在的目录)。
关键区别总结
| 场景 | 打包前(Python 脚本) | 打包后(可执行文件) |
|---|---|---|
| 路径决定因素 | 终端执行脚本时的当前目录 | 取决于启动方式: - 命令行启动:终端当前目录 - 文件管理器双击:通常为 exe 所在目录 |
| 与脚本/exe 位置的关系 | 无关(仅由终端位置决定) | 无关(除非是双击方式启动) |
sys.executable
打包前
在普通 Python 脚本中,sys.executable 返回 当前 Python 解释器的可执行文件(exe) 路径,例如:
import sys
print(sys.executable)
# 输出示例: "D:\\Python3.10\\python.exe"
打包后
PyInstaller 打包后的可执行文件运行时,sys.executable 会指向 当前运行的打包文件(exe) 本身,而非 Python 解释器。例如:
import sys
print(sys.executable)
# 输出示例: "C:\\dist\\my_app.exe"
此变化是因为 PyInstaller 将 Python 解释器和依赖库“冻结”到可执行文件中。
sys.argv
打包前
sys.argv 是一个列表,包含命令行参数。第一个元素 sys.argv[0] 通常是当前脚本文件名,其余元素是脚本接收到的命令行参数。
注意:sys.argv[0]就是在Path.cwd()下指定的要执行的Python脚本文件,所以可以是绝对路径,也可以是Path.cwd()的相对路径
import sys
print(f'sys.argv[0] = {sys.argv[0]}')
运行命令
E:\workspace-pycharm\one-api>python E:\workspace-pycharm\install_demo\src\main.py arg1 arg2
sys.argv[0] = E:\workspace-pycharm\install_demo\src\main.py
E:\workspace-pycharm\one-api>cd ..\install_demo
E:\workspace-pycharm\install_demo>python src\main.py arg1 arg2
sys.argv[0] = src\main.py
E:\workspace-pycharm\install_demo>cd src
E:\workspace-pycharm\install_demo\src>python main.py arg1 arg2
sys.argv[0] = main.py
打包后
打包后的可执行文件运行时,sys.argv[0] 会变为可执行文件的路径,后续参数保持不变:
import sys
print(sys.argv)
# 运行命令: my_app.exe arg1 arg2
# 输出: ['my_app.exe', 'arg1', 'arg2']
Path(__file__)
打包前
__file__ 表示当前脚本的文件路径,Path(__file__).resolve() 可获取绝对路径:
from pathlib import Path
print(Path(__file__).resolve())
# 输出示例: "D:\\project\\my_script.py"
打包后
PyInstaller 会将脚本打包到临时目录中,__file__ 的路径会指向解压后的临时文件夹。例如:
from pathlib import Path
print(Path(__file__).resolve())
# 输出示例: "C:\\Users\\User\\AppData\\Local\\Temp\\_MEI1234\\my_script.py"
若需获取打包后的可执行文件路径,可结合 sys.executable:
from pathlib import Path
import sys
print(Path(sys.executable).resolve())
# 输出示例: "C:\\dist\\my_app.exe"
应用场景与解决方案
- 一起被打包的资源文件路径问题
若脚本依赖一些一起被打包的资源文件(如js文件、图片),打包后直接使用Path(__file__)会失败。推荐利用PyInstaller特有的sys._MEIPASS变量(类型为str)来解决(根据项目结构视情况稍作调整):
import sys
from pathlib import Path
if getattr(sys, 'frozen', False):
# 运行在 PyInstaller 打包后的环境中
# sys._MEIPASS 是在使用 PyInstaller 打包 Python 程序时生成的一个特殊属性。它指向一个临时目录,该目录包含了程序运行所需的所有依赖文件
base_dir = Path(sys._MEIPASS)
else:
# 运行在本地环境中。
base_dir = Path(__file__).parent
resource_path = base_dir / 'resource'
- 非打包的配置文件路径问题
打包后若需访问与可执行文件同目录的非打包的文件(如配置文件),不要依赖Path.cwd(),因为它可能因启动方式不同而变化。正确做法是通过sys.executable获取可执行文件的绝对路径,再提取其所在目录(根据项目结构视情况稍作调整):
import sys
from pathlib import Path
# 获取可执行文件所在的绝对目录(打包后有效)
if getattr(sys, 'frozen', False):
# 打包后的场景(PyInstaller 会设置 `frozen` 属性)
base_dir = Path(sys.executable).parent.resolve()
else:
# 未打包的场景(直接运行脚本)
base_dir = Path(__file__).parent.resolve()
# 使用 base_dir 构造资源路径(如读取同目录的 config.yaml)
config_path = base_dir / "config.yaml"
- 参数传递与调试
打包后的程序仍可通过命令行传递参数,但需注意sys.argv[0]的变化。调试时建议输出完整参数列表以确认行为。
总结
| 变量/场景 | 打包前 | 打包后 |
|---|---|---|
Path.cwd() |
终端执行脚本时的当前目录 | 取决于启动方式: - 命令行启动:终端当前目录 - 文件管理器双击:通常为 exe 所在目录 |
sys.executable |
Python 解释器路径 | 可执行文件自身路径 |
sys.argv[0] |
脚本文件名 | 可执行文件名 |
Path(__file__) |
脚本文件绝对路径 | 临时解压目录中的路径 |
理解这些差异后,可以更安全地处理路径和资源加载问题,确保程序在打包前后均能正常运行。
更多推荐




所有评论(0)