4. 包的分发基础:setuptools库介绍、setup.py文件的编写、包的元数据配置、包的构建
好,咱们进入实战环节了。前面几章我们把模块和包的结构讲清楚了,但有个问题——你写好的包怎么给别人用?总不能让人家去GitHub上手动下载文件夹吧?
这就引出了包的分发机制。说白了,就是把你写的代码打包成一个标准格式,扔到PyPI上,别人一个pip install就能装好。我刚开始学的时候觉得这步挺玄乎的,后来发现其实就是写一个setup.py文件的事。
4.1 setuptools库介绍
setuptools是Python官方推荐的打包工具。它替代了老旧的distutils,功能更强大。你想想看,如果没有它,你要手动处理依赖关系、版本号、元数据……那得多痛苦。
我个人习惯用setuptools配合wheel一起用。为什么?因为wheel格式的包安装速度更快,而且不需要执行setup.py里的代码。嗯,这里要注意:wheel不是setuptools自带的,需要单独安装。
pip install setuptools wheel。我建议你在虚拟环境里操作,避免污染全局Python环境。
4.2 setup.py文件的编写
这是整个分发流程的核心。setup.py是一个Python脚本,它调用setuptools的setup()函数,告诉打包工具你的包长什么样。
来看一个最基础的例子:
from setuptools import setup, find_packages
setup(
name='myutils',
version='0.1.0',
packages=find_packages(),
install_requires=[
'requests>=2.25.0',
'numpy>=1.19.0',
],
)
这段代码干了三件事:
- 告诉setuptools包名叫
myutils - 自动发现所有子包(
find_packages()会扫描当前目录下的所有__init__.py文件) - 声明了两个依赖:requests和numpy
我在项目中遇到过一个问题:有人把packages参数写成了手动列表,结果漏掉了一个子包,用户安装后导入时报错。所以,能用find_packages()就别手写。
4.3 包的元数据配置
元数据就是包的「身份证」。它告诉用户这个包是谁写的、干什么用的、版本号是多少。配置好了,用户在PyPI上就能看到完整信息。
常用的元数据字段:
| 字段名 | 说明 | 示例 |
|---|---|---|
name |
包名,必须唯一 | 'myutils' |
version |
版本号,遵循语义化版本 | '0.1.0' |
author |
作者姓名 | '张三' |
author_email |
作者邮箱 | 'zhangsan@example.com' |
description |
简短描述 | '一个实用的工具包' |
long_description |
详细描述,通常从README读取 | open('README.md').read() |
url |
项目主页 | 'https://github.com/...' |
classifiers |
分类标签 | ['Programming Language :: Python :: 3'] |
一个更完整的例子:
from setuptools import setup, find_packages
with open('README.md', 'r', encoding='utf-8') as f:
long_description = f.read()
setup(
name='myutils',
version='0.1.0',
author='张三',
author_email='zhangsan@example.com',
description='一个实用的工具包',
long_description=long_description,
long_description_content_type='text/markdown',
url='https://github.com/zhangsan/myutils',
packages=find_packages(),
classifiers=[
'Programming Language :: Python :: 3',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
],
python_requires='>=3.6',
install_requires=[
'requests>=2.25.0',
],
)
long_description_content_type上栽过跟头。如果你用Markdown写的README,一定要加上long_description_content_type='text/markdown',否则PyPI会把它当纯文本渲染,效果惨不忍睹。
4.4 包的构建:sdist和bdist_wheel
写好setup.py后,下一步就是构建。构建会生成一个可分发的文件,你可以上传到PyPI或者直接发给别人。
两种主要的构建方式:
- sdist(源码分发包):生成
.tar.gz文件,包含源码。用户安装时需要编译,速度慢。 - bdist_wheel(wheel分发包):生成
.whl文件,是预编译的。安装时直接解压,速度快。
我个人强烈推荐用wheel格式。为什么?因为用户拿到.whl文件后,安装就是秒级的事。而sdist在某些平台上可能因为缺少编译工具而失败。
构建命令:
# 构建源码包
python setup.py sdist
# 构建wheel包
python setup.py bdist_wheel
# 或者一步到位,两个都构建
python setup.py sdist bdist_wheel
执行后,会在项目目录下生成一个dist/文件夹,里面就是构建好的包。
来看一个构建流程的示意图:
构建完成后,你可以用twine工具上传到PyPI。不过那是下一章的内容了,咱们先把构建这一步练熟。
setup.py是包分发的入口,必须放在项目根目录- 元数据要写全,尤其是
name和version,缺一不可 - 优先使用
bdist_wheel构建,用户体验更好 - 构建产物在
dist/目录下,不要手动修改
嗯,这一章的内容就这些。说白了,包分发就是把你的代码「包装」成一个标准产品。写setup.py就像填一份快递单——写清楚寄件人、收件人、物品名称,剩下的交给setuptools去处理。
下一章我们会讲如何把构建好的包上传到PyPI,以及如何管理版本号。到时候你会看到,整个流程其实比想象中简单得多。