本文在 macOS Monterey 及 Python 3.9.6 环境下测试通过
本文是面向百度编写的,如果你希望了解这些内容欢迎继续浏览,如果你希望避免踩坑快速通关,可以阅读官方文档 Packaging Python Projects
模块与包 在 Python 中一个文件就是一个 模块 Module,是 Python 中一个单独的命名空间,这个命名空间包括了下面的内容:类、函数、常量、变量等。当然,Python 中还支持使用 C 语言编写模块并实现运行时加载,本文不涉及这方面的内容。
模块文件的代码中通常不能有任何输出,这些输出在执行 import 的时候就会被执行 如果希望以单独脚本形式执行时还是能够输出信息,可以添加 if __name__ = '__main__'
判断 这是因为 import 的时候,python 会给模块增加 __name__
属性,单独执行时 __name__
会等于 __main__
当模块越来越多时,我们需要包 Package 来帮我们组织管理,同时包也是 Pypi 上共享的最小单位。包通常对应一个文件夹,包括了一个或者多个模块。在包代码文件夹下一定要有 __init__.py
文件,另外可能还有一些 python 文件或者其他包的文件夹。相较于模块来说,包中的内容更多:文档、测试案例、安装方法以及必要的数据文件等等都可以放在包中。
本文以 mp3tag 为示例代码来说明一个包的开发与发布过程,看一下它的目录结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ tree . . ├── LICENSE ├── README.md ├── examples │ └── tag_example.py ├── mp3tag │ ├── __init__.py │ ├── mp3tag.py │ ├── tag_reader.py │ └── tag_writer.py └── setup.py 3 directories, 10 files
本地开发测试 几种方式
使用 virtualenv
使用集成了测试环境的 IDE,例如 pycharm
使用 sys.path
python 解析器在执行的时候,会从 sys.path
变量保存的路径中按顺序搜索引用的包,因此本地测试时,可以通过向这个变量追加路径,来实现本地测试。模块加载后,我们可以通过 __file__
属性获取模块所在的路径。
1 2 3 >>> import adtk>>> print (adtk.__file__)/usr/local/lib/python3.9 /site-packages/adtk/__init__.py
在这个环节,我们除了编写我们的业务逻辑之外,还需要编写 setup.py
文件,还有一种编写 setup.cfg
的方法,本文没有采用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from setuptools import setup, find_packagesVERSION = '0.0.1' DESCRIPTION = 'MP3 tag information reader and writer.' LONG_DESCRIPTION = 'MP3 contains many information about the music and stored in the tag. This package support read and write id3v2 tag to the mp3 file.' setup( name='mp3tag' , version=VERSION, author='Wang Shiqiang' , author_email='cocowool@qq.com' , description=DESCRIPTION, long_description=LONG_DESCRIPTION, packages=find_packages(), install_requires=[], keywords=['mp3' ,'id3' ,'id3v2' ], classifiers=[] )
创建发布文件 在项目的根文件夹下,执行下面的命令,需要提前安装 build 模块。
1 2 3 $ python3 -m build * Creating venv isolated environment... * Installing packages in isolated environment... (setuptools>=42)
整个过程比较慢,执行完成后,可以看到 dist 文件夹下多了两个文件。
1 2 3 4 5 6 $ ll dist total 64 drwxr-xr-x 4 shiqiang staff 128B Jun 5 15:18 . drwxr-xr-x 12 shiqiang staff 384B Jun 5 15:17 .. -rw-r--r-- 1 shiqiang staff 16K Jun 5 15:18 mp3tag-0.0.1-py3-none-any.whl -rw-r--r-- 1 shiqiang staff 15K Jun 5 15:17 mp3tag-0.0.1.tar.gz
其中 tar.gz
文件是安装包,whl
结尾的文件是分发说明文件。
发布到 pypi pypi 是一个公共的 python 包共享分发平台,全称「Python Package Index」,类似 npmjs。将开发的包发布到 pypi 之后,我们可以方便的通过 pip3 install
安装使用我们开发的包,这对于开源社区的发展繁荣是非常好的机制。当然,如果是你一名企业内部的开发者,对于任何引入到工程中的包还是需要注意进行安全检查,避免引入不必要的麻烦。
发布到 pypi 需要首先有一个 pypi 的账号,还需要在 pypi 网站上生成 API Key。
如果使用 twine 上传,需要按照网站的提示准备 .pypirc 文件。
如果离上一个版本过去的时间比较长,可能存在上传失败的问题,官方提供了一个 TroubleShooting 的页面。
1 2 3 4 5 6 7 8 9 10 11 $ python3 -m twine upload dist/* Uploading distributions to https://upload.pypi.org/legacy/ Enter your username: cocowool Enter your password: Uploading mp3tag-0.0.1-py3-none-any.whl 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 19.8/19.8 kB • 00:01 • 19.7 MB/s Uploading mp3tag-0.0.1.tar.gz 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 19.5/19.5 kB • 00:00 • 30.9 MB/s View at: https://pypi.org/project/mp3tag/0.0.1/
安装测试 1 2 3 4 5 $ pip3 install mp3tag Collecting mp3tag Downloading mp3tag-0.0.1-py3-none-any.whl (15 kB) Installing collected packages: mp3tag Successfully installed mp3tag-0.0.1
至此,一个自己开发的 Python 包就发布成功了。
参考资料
How to Build your very first python package
Pypi
Making a Python Package
How to Create a Python Package
Packaging and distributing projects
python tutorial : class
Python Modules and Packages – An Introduction
Packaging Python Projects
解决TypeError: ‘module’ object is not callable问题
pycache 是个什么鬼?