跳到主要内容鸿蒙电脑开发 Python whl 打包 | 极客日志Python
鸿蒙电脑开发 Python whl 打包
在鸿蒙电脑上制作 Python whl 分发包的流程。内容包括 whl 文件格式说明、优势及命名规范。详细步骤涵盖环境准备、打包工具安装(wheel, build, pytest)、工程结构搭建、pyproject.toml 配置编写、执行打包命令以及本地安装测试与卸载方法。旨在帮助开发者掌握 Python 二进制包的标准化发布流程。
Pythonist863 浏览 鸿蒙电脑开发 Python-whl 打包
什么是 whl 文件
whl(Wheel)是 Python 的一种打包格式,用于发布和安装 Python 软件包。与传统的.tar.gz 或.zip 文件相比,.whl文件具有更好的性能和易用性,它可以包含预编译的二进制文件、Python 代码、依赖关系和其他必需的资源。.whl 文件允许开发者将包的所有内容打包在一个文件中,使安装过程更加简单和方便。
whl 格式本质上是一个压缩包,里面包含了 py 文件,以及经过编译的 pyd 文件,可以在不具备编译环境的情况下,选择合适自己的 Python 环境进行安装,目前 wheel被认为是 Python 的二进制包的标准格式。
whl 优势
- 安装速度快 - 无需运行 setup.py,直接解压复制文件即可
- 免编译 - 无需编译意味着不会出现编译时的环境问题
- 避免执行不安全代码 - 安装源码包时会执行 setup.py 中的代码,若安装脚本中偷跑一些代码,是很危险的事情
- 支持跨平台 - 通过文件名中的字段指明兼容的平台和 Python 版本
- 依赖管理简单 - 通过元数据明确表明依赖关系
whl 文件名含义
whl 文件名遵循 PEP 427 规范,标准格式为:
{distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl
以 flask举例:flask-3.0.3-py3-none-any.whl
| 字段 | 含义说明 |
|---|
| distribution | 包名(如 flask) |
| version | 版本号(如 3.0.3) |
| build tag | 构建序号(可选,如 1) |
| python tag | Python 版本标签(如 py3 表示 Python 3) |
| abi tag | ABI 标签(如 none 表示无 ABI 依赖) |
| platform tag | 平台标签(如 any 表示跨平台,win_amd64 表示 Windows 64 位) |
这个包告诉我们,这是一个依赖 Python 3可跨平台的无ABI依赖的flask3.0.3版本的 Python 软件分发包
再以 numpy举例:numpy-1.21.0-cp39-cp39-linux_armv7l.whl
这个文件名告诉我们:这是一个依赖 CPython 3.9的仅在 Linux ARMv7架构(如树莓派)且依赖 与 CPython 3.9 兼容的 ABI的numpy1.21.0版本的 Python 软件分发包
这些包可以在pypi 源找到,可以自行研究下
另外也可以参考一些国内源,比较推荐 aliyun
可以直接访问 http://mirrors.aliyun.com/pypi/simple/ + 包名来查看,仍然以 numpy 举例:http://mirrors.aliyun.com/pypi/simple/numpy/ 下包含无数个不同平台,版本等等组合关系的分发软件包

pip 能够确切通过命名来检索适合你的系统的 Python 软件分发包是什么,避免了下载不兼容包的问题。
制作第一个 whl 包
前面介绍了命名规范,我们可以简单理解,none-any形态的包是不依赖任何接口或 C 接口的,这次我们先介绍如何制作一个 none-any类型的包,这类包有充分的跨平台属性,不依赖任何 native 接口,仅需要依赖对应的 Python 运行时
环境准备
在鸿蒙电脑上制作 whl 包,需要具备 Python 环境和基础工具链,建议按照以下环境部署:
- 设备:我使用的 MateBook Pro 已经升级到
6.0.0.115版本,建议升级到该版本以上
- 工具链:应用市场安装 DevBox
- Python 环境:应用市场安装 Python 安装器
在终端中执行 python --version、git version、clang --version确保以上环境部署成功,如图所示
安装打包工具
接下来需要安装几个 python 的打包工具,在终端中依次执行下面的命令
python -m pip install wheel
看到以下结果证明安装成功,wheel 工具安装到 /storage/Users/currentUser/.local下
python -m pip install build
python -m pip install pytest
编写工程代码
我们编写一个典型案例 simple_math,包含加减乘除的封装库
工程结构如下:
simple_math/
├── src/
│ └── simple_math/
│ ├── __init__.py
│ ├── add.py
│ ├── sub.py
│ ├── mult.py
│ └── div.py
├── test/
│ └── test_ops.py
├── examples/
│ └── example.py
├── README.md
├── LICENSE
└── pyproject.toml
def add(a: float, b: float) -> float:
"""
将两个数字相加
Args:
a (float): 第一个数字
b (float): 第二个数字
Returns:
float: 两个数字的和
"""
return float(a + b)
def div(a: float, b: float) -> float:
"""
将第一个数字除以第二个数字
Args:
a (float): 被除数
b (float): 除数
Returns:
float: 两个数字的商
Raises:
ZeroDivisionError: 当除数为零时抛出
"""
if b == 0:
raise ZeroDivisionError("除数不能为零")
return float(a / b)
def sub(a: float, b: float) -> float:
return float(a - b)
def mult(a: float, b: float) -> float:
return float(a * b)
""" 简单数学计算包 提供加减乘除基本运算 """
__version__ = "0.1.0"
from .add import add
from .sub import sub
from .mult import mult
from .div import div
import pytest
from simple_math.add import add
from simple_math.sub import sub
from simple_math.mult import mult
from simple_math.div import div
class TestAdd:
"""测试加法功能"""
def test_add(self):
assert add(2, 3) == 5.0
class TestSub:
"""测试减法功能"""
def test_sub(self):
assert sub(5, 3) == 2.0
class TestMult:
"""测试乘法功能"""
def test_mult_positive_numbers(self):
assert mult(2, 3) == 6.0
class TestDiv:
"""测试除法功能"""
def test_div(self):
assert div(6, 3) == 2.0
def test_div_by_zero(self):
with pytest.raises(ZeroDivisionError):
div(5, 0)
from simple_math import add, sub, mult, div
def main():
"""演示所有功能的使用"""
print("=== math_ops 包使用示例 ===\n")
print("数学运算:")
print(f"2 + 3 = {add(2, 3)}")
print(f"5 - 3 = {sub(5, 3)}")
print(f"2 * 3 = {mult(2, 3)}")
print(f"6 / 3 = {div(6, 3)}")
print("\n" + "="*40 + "\n")
print("错误处理:")
try:
result = div(5, 0)
print(f"5 / 0 = {result}")
except ZeroDivisionError as e:
print(f"错误:{e}")
if __name__ == "__main__":
main()
编写打包信息
[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "simple-math"
version = "0.1.0"
description = "一个简单的数学计算"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT"}
authors = [
{name = "your_name", email = "[email protected]"}
]
keywords = ["math", "calculator", "hello-world", "example"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Education",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Education",
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = []
[project.urls]
Homepage = "https://example.com/yourusername/simple-math"
Documentation = "https://example.com/yourusername/simple-math#readme"
Repository = "https://example.com/yourusername/simple-math"
Issues = "https://example.com/yourusername/simple-math"
[tool.setuptools]
package-dir = {"" = "src"}
[tool.setuptools.packages.find]
where = ["src"]
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-v"
1、构建系统配置
[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"
- requires:构建项目所需的工具(如 setuptools 和 wheel)
- build-backend:指定构建后端(setuptools)
2、项目元数据
[project]
name = "simple-math"
version = "0.1.0"
description = "一个简单的数学计算"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT"}
authors = [
{name = "your_name", email = "[email protected]"}
]
keywords = ["math", "calculator", "hello-world", "example"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Education",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Education",
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = []
- name/version:包名和版本号
- description:项目简介
- readme:README 文件路径
- requires-python:Python 版本要求(≥3.8)
- license:MIT 许可证
- authors:作者信息
- keywords:关键词标签
- classifiers:项目分类(如开发状态、目标用户、编程语言)
- dependencies:项目依赖(当前为空)
3、项目 URL
[project.urls]
Homepage = "https://example.com/yourusername/simple-math"
Documentation = "https://example.com/yourusername/simple-math#readme"
Repository = "https://example.com/yourusername/simple-math"
Issues = "https://example.com/yourusername/simple-math"
4、包发现配置
[tool.setuptools]
package-dir = {"" = "src"}
[tool.setuptools.packages.find]
where = ["src"]
- package-dir:源码目录(src)
- packages.find:在 src 目录下查找包
5、测试配置
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-v"
- testpaths:测试目录(tests)
- addopts:测试运行参数(详细输出 -v)
写好 README 和 LICENSE 文件(不详细介绍)
执行打包动作
cd simple_math
python -m build --wheel
此时我们再次查看工程目录,可以看到多了一个 build 目录,包含 dist 和 lib 目录,这部分均为打包文件,生成的 whl 包在 dist 下,名称为 simple_math-0.1.0-py3-none-any.whl,属于我们期望的 none-any类型,另外 egg 也正常产生了
本地安装和运行测试
python -m pip install dist/simple_math-0.1.0-py3-none-any.whl
python -c "import simple_math; print(simple_math.__version__)"
结果如下则证明安装成功,simple-math安装到 ~/.local/lib/python3.12/site-packages/simple_math目录下
python -m pip list | grep simple-math
卸载
通过 python -m pip uninstall <module>可以卸载我们安装的软件包
python -m pip uninstall simple_math
可以看到在用户同意后(Y),我们刚安装的 simple_math模块已经移除,在 pip list以及 ~/.local/lib/python3.12/site-packages目录下均无法查询到对应的模块
总结
相关免费在线工具
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
- HTML转Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
- JSON 压缩
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online