技术场景:
需分发的Python工具要求终端用户可动态修改执行逻辑将Python环境与指定库(如NumPy/Pandas)嵌入可执行文件实现"一次打包,动态扩展"的轻量化解决方案。
▌ 架构设计原理
1. 双模运行时识别
# 核心判断逻辑(适配开发模式与编译模式)
def get_runtime_path():
if getattr(sys, 'frozen', False):
return os.path.dirname(sys.executable) # 编译模式取执行文件路径
return os.path.dirname(__file__) # 开发模式取脚本路径
设计优势:
- 开发阶段与发布版本使用同一套代码
- 避免硬编码路径引发的跨平台兼容问题
2. 动态脚本加载机制
def load_script(script_name):
target_path = os.path.join(get_runtime_path(), script_name)
if os.path.exists(target_path):
with open(target_path, 'r', encoding='utf-8') as f:
exec(f.read(), globals()) # 在全局命名空间执行脚本
3. 架构图
▌ 基础功能实现
1. 编写main.py和Run.py文件(名称随意)
main.py
import os
import sys
# === 预先导入之后可能会用到的模块 ===
import numpy
import pandas
# 核心判断逻辑(适配开发模式与编译模式)
def get_runtime_path():
if getattr(sys, 'frozen', False):
return os.path.dirname(sys.executable) # 编译模式取执行文件路径
return os.path.dirname(__file__) # 开发模式取脚本路径
# 这里一定要定义一个main函数
def main():
# 导入一个可以被修改的脚本代码“Run.py”,后续可以通过它指定要被运行的脚本
current_path = get_runtime_path()
ScriptPath = os.path.join(current_path, "Run.py")
if os.path.isfile(ScriptPath):
with open(ScriptPath, 'r', encoding='utf-8') as file:
exec(file.read(),globals())
# 程序入口
if __name__ == "__main__":
main()
Run.py
import os
import sys
# 核心判断逻辑(适配开发模式与编译模式)
def get_runtime_path():
if getattr(sys, 'frozen', False):
return os.path.dirname(sys.executable) # 编译模式取执行文件路径
return os.path.dirname(__file__) # 开发模式取脚本路径
def load_script(script_name):
target_path = os.path.join(get_runtime_path(), script_name)
if os.path.exists(target_path):
with open(target_path, 'r', encoding='utf-8') as f:
exec(f.read(), globals()) # 在全局命名空间执行脚本
# def main():
script_name = "example_1.py"
load_script(script_name)
script_name = "example_2.py"
load_script(script_name)
# if __name__ == "__main__":
# main()
由于实际运行时上方代码Run.py由main.exe调用,将直接和main.exe共用全局命名空间中的os和sys库,因此
2. 编译 main.py :
pyinstaller --onedir main.py
若没有安装pyinstaller,请先使用pip安装:
pip install pyinstaller
编译完的文件如下:
your_project_folder/
│
├──── build/ → 没有用,可以删除
├──── dist/ → 打包后的程序文件夹
│ └─── main/
│ ├─── _internal/ → 需要用到的库文件会被放在这里
│ └─── main.exe → 打包后的可执行程序
│
└──── main.spec → 打包配置文件,可以修改它来定制打包过程
_internal/ 和 main.exe → 可以一起拿出来放在其它位置(需放在同一路径下)
3. 测试运行效果
运行 main.exe :
test_main.bat
.\main.exe
pause
运行 test_main.bat 文件,查看效果:
D:\test>.\main.exe
This script is running as a compiled executable.
This script is running as a compiled executable.
一维数组:
[1 2 3 4 5]
一维数组加10:
[11 12 13 14 15]
一维数组乘2:
[ 2 4 6 8 10]
二维数组:
[[1 2]
[3 4]]
矩阵乘法结果:
[[ 7 10]
[15 22]]
原始DataFrame:
Name Age City
0 Alice 24 New York
1 Bob 27 Los Angeles
2 Charlie 22 Chicago
3 David 32 Houston
年龄大于25的行:
Name Age City
1 Bob 27 Los Angeles
3 David 32 Houston
按年龄升序排序后的DataFrame:
Name Age City
2 Charlie 22 Chicago
0 Alice 24 New York
1 Bob 27 Los Angeles
3 David 32 Houston
描述性统计量:
Age
count 4.000000
mean 26.250000
std 4.349329
min 22.000000
25% 23.500000
50% 25.500000
75% 28.250000
max 32.000000
D:\test>pause
请按任意键继续. . .
▌ 例程(附)
example_1.py
import numpy as np
# 创建一个一维数组
arr1 = np.array([1, 2, 3, 4, 5])
# 创建一个二维数组(矩阵)
arr2 = np.array([[1, 2], [3, 4]])
# 数组加法
arr_sum = arr1 + 10
# 数组乘法(元素级)
arr_prod = arr1 * 2
# 矩阵乘法
mat_prod = np.dot(arr2, arr2)
# 打印结果
print("一维数组:")
print(arr1)
print("一维数组加10:")
print(arr_sum)
print("一维数组乘2:")
print(arr_prod)
print("二维数组:")
print(arr2)
print("矩阵乘法结果:")
print(mat_prod)
运行结果:(example_1.py)
一维数组:
[1 2 3 4 5]
一维数组加10:
[11 12 13 14 15]
一维数组乘2:
[ 2 4 6 8 10]
二维数组:
[[1 2]
[3 4]]
矩阵乘法结果:
[[ 7 10]
[15 22]]
example_2.py
import pandas as pd
# 创建一个简单的DataFrame
data = {
'Name': ['Alice', 'Bob', 'Charlie', 'David'],
'Age': [24, 27, 22, 32],
'City': ['New York', 'Los Angeles', 'Chicago', 'Houston']
}
df = pd.DataFrame(data)
# 显示DataFrame
print("原始DataFrame:")
print(df)
# 数据筛选:选择年龄大于25的行
filtered_df = df[df['Age'] > 25]
print("\n年龄大于25的行:")
print(filtered_df)
# 数据排序:按年龄升序排序
sorted_df = df.sort_values(by='Age')
print("\n按年龄升序排序后的DataFrame:")
print(sorted_df)
# 计算描述性统计量
stats = df.describe()
print("\n描述性统计量:")
print(stats)
运行结果:(example_2.py)
原始DataFrame:
Name Age City
0 Alice 24 New York
1 Bob 27 Los Angeles
2 Charlie 22 Chicago
3 David 32 Houston
年龄大于25的行:
Name Age City
1 Bob 27 Los Angeles
3 David 32 Houston
按年龄升序排序后的DataFrame:
Name Age City
2 Charlie 22 Chicago
0 Alice 24 New York
1 Bob 27 Los Angeles
3 David 32 Houston
描述性统计量:
Age
count 4.000000
mean 26.250000
std 4.349329
min 22.000000
25% 23.500000
50% 25.500000
75% 28.250000
max 32.000000