Python 包管理全解析
在 Python 的开发中,包管理是一项至关重要的技能。合理的包管理能够帮助开发者更高效地组织代码、分享工具和模块,同时避免包冲突等问题。下面将为大家详细介绍 Python 包管理的相关内容。
入口点与脚本安装
入口点是一个较为复杂的概念,但从高层次理解,它可以让你将脚本作为命令行工具安装到用户的路径中。要实现这一点,只需遵循特定的语法并定义一个运行命令行工具的函数。
向 Python 包索引注册包
如果你编写了一个很棒的工具或有用的模块,自然希望与他人分享,而将包上传到 Python 包索引(Python Package Index)是一个相对简单的过程。不过,这个过程与创建 egg 稍有不同,需要注意两点:
- 在
long_description
中包含 ReST(reStructuredText)格式的描述。ReST 格式的文档在上传到 PyPI 时会被转换为 HTML,你可以使用 Aaron Hillegass 创建的 ReSTless 工具预览格式化后的文本,确保格式正确。如果 ReST 格式不正确,上传的文档将显示为纯文本而非 HTML。
- 提供
download_url
值,它能告诉
easy_install
在哪里搜索你的包。你可以提供一个页面链接,
easy_install
会自动找到包或 egg,也可以直接提供你创建的 egg 的链接。
以下是一个用于上传到 Python 包索引的
setup.py
示例:
#!/usr/bin/env python
# liten 0.1.4.2 -- deduplication command - line tool
#
# Author: Noah Gift
try:
from setuptools import setup, find_packages
except ImportError:
from ez_setup import use_setuptools
use_setuptools()
from setuptools import setup, find_packages
import os,sys
version = '0.1.4.2'
f = open(os.path.join(os.path.dirname(__file__), 'docs', 'index.txt'))
long_description = f.read().strip()
f.close()
setup(
name='liten',
version='0.1.4.2',
description='a de - duplication command line tool',
long_description=long_description,
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
],
author='Noah Gift',
author_email='noah.gift@gmail.com',
url='http://pypi.python.org/pypi/liten',
download_url="http://code.google.com/p/liten/downloads/list",
license='MIT',
py_modules=['virtualenv'],
zip_safe=False,
py_modules=['liten'],
entry_points="""
[console_scripts]
liten = liten:main
""",
)
使用这个
setup.py
文件,通过执行以下命令可以“自动”向 Python 包索引注册包:
$ python setup.py register
这个
setup.py
文件比之前的示例增加了一些额外的字段,如
description
、
long_description
、
classifiers
、
author
和
download_url
。入口点允许工具从命令行运行并安装到默认的脚本目录中。
更多学习资源
以下是一些重要的学习资源:
- Easy install:http://peak.telecommunity.com/DevCenter/EasyInstall
- Python eggs:http://peak.telecommunity.com/DevCenter/PythonEggs
- The setuptools module:http://peak.telecommunity.com/DevCenter/setuptools
- The package resources module:http://peak.telecommunity.com/DevCenter/PkgResources
- Architectural overview of pkg_resources and Python eggs in general
- Python 邮件列表:http://mail.python.org/pipermail/distutils-sig/
Distutils 包管理
虽然目前很多人更喜欢使用
setuptools
来创建和分发包,但了解
distutils
包的工作原理、
setuptools
的增强之处和不足之处仍然很重要。
当使用
distutils
创建用于分发的包时,通常通过以下命令安装包:
python setup.py install
构建用于分发的包时,主要涵盖以下四个主题:
1. 如何编写一个
setup
脚本(即
setup.py
文件)
2.
setup.py
文件中的基本配置选项
3. 如何构建源分发
4. 创建二进制文件,如 rpms、Solaris pkgtool 和 HP - UX swinstall
下面通过一个具体示例展示
distutils
的工作流程:
步骤 1:创建代码
#!/usr/bin/env python
#A simple python script we will package
#Distutils Example. Version 0.1
class DistutilsClass(object):
"""This class prints out a statement about itself."""
def __init__(self):
print "Hello, I am a distutils distributed script." \
"All I do is print this message."
if __name__ == '__main__':
DistutilsClass()
步骤 2:在脚本所在目录创建
setup.py
文件
#Installer for distutils example script
from distutils.core import setup
setup(name="distutils_example",
version="0.1",
description="A Completely Useless Script That Prints",
author="Joe Blow",
author_email = "joe.blow@pyatl.org",
url = "http://www.pyatl.org")
这里向
setup()
函数传递了几个关键字参数,用于通过元数据标识这个包。这只是一个简单示例,实际上还有更多选项,如处理多个依赖项等。
步骤 3:创建分发包
在脚本、
README
和
setup.py
文件所在的同一目录下执行以下命令,即可轻松创建源分发包:
python setup.py sdist
执行该命令后,会得到如下输出:
running sdist
warning: sdist: manifest template 'MANIFEST.in' does not exist
(using default file list)
writing manifest file 'MANIFEST'
creating distutils_example-0.1
making hard links in distutils_example-0.1...
hard linking README.txt distutils_example-0.1
hard linking setup.py distutils_example-0.1
creating dist
tar -cf dist/distutils_example-0.1.tar distutils_example-0.1
gzip -f9 dist/distutils_example-0.1.tar
removing 'distutils_example-0.1' (and everything under it)
从输出可以看出,现在其他人只需解包并使用以下命令安装:
python setup.py install
如果要构建二进制文件,以下是一些示例命令:
- 构建 rpm:
python setup.py bdist_rpm
- 构建 Solaris pkgtool:
python setup.py bdist_pkgtool
- 构建 HP - UX swinstall:
python setup.py bdist_sdux
最后,在分发包时,你可能希望自定义安装目录。通常,构建和安装过程是一次性完成的,但你也可以选择自定义构建目录,例如:
python setup.py build --build-base=/mnt/python_src/ascript.py
实际运行安装命令时,它会将构建目录中的所有内容复制到安装目录。默认情况下,安装目录是执行命令的 Python 环境中的
site-packages
目录,你也可以指定自定义安装目录,如 NFS 挂载点。
Buildout 包管理工具
Buildout 是 Zope 公司的 Jim Fulton 创建的一个工具,用于管理新应用的“构建”。这些应用可以是 Python 程序,也可以是其他程序,如 Apache。Buildout 的主要目标之一是让构建过程在不同平台上可重复。下面将分别介绍 Buildout 的使用和开发。
使用 Buildout
虽然很多使用 Zope 技术的人了解 Buildout,但在 Python 社区的其他领域,它还是一个相对陌生的工具。Buildout 是部署 Plone 的推荐机制,Plone 是一个企业级内容管理系统,在 Buildout 出现之前,其安装过程非常复杂,而现在 Buildout 让安装变得轻而易举。
很多人不知道,Buildout 还可以用于管理 Python 环境。它只需要两个东西:
- 最新版本的
bootstrap.py
,可以从以下链接下载:http://svn.zope.org/
checkout
/zc.buildout/trunk/bootstrap/bootstrap.py
- 一个
buildout.cfg
文件,包含要安装的“recipes”或“eggs”的名称。
下面以安装 Noah 编写的去重命令行工具
liten
为例,展示如何使用 Buildout:
步骤 1:下载
bootstrap.py
脚本
mkdir -p ~/src/buildout_demo
curl http://svn.zope.org/*checkout*/zc.buildout/trunk/bootstrap/bootstrap.py > ~/src/buildout_demo/bootstrap.py
步骤 2:定义简单的
buildout.cfg
文件
如果没有
buildout.cfg
文件就运行
bootstrap.py
脚本,会得到如下错误:
$ python bootstrap.py
While:
Initializing.
Error: Couldn't open /Users/ngift/src/buildout_demo/buildout.cfg
以下是一个示例
buildout.cfg
文件:
[buildout]
parts = mypython
[mypython]
recipe = zc.recipe.egg
interpreter = mypython
eggs = liten
将该文件保存为
buildout.cfg
后,再次运行
bootstrap.py
脚本,会得到如下输出:
$ python bootstrap.py
Creating directory '/Users/ngift/src/buildout_demo/bin'.
Creating directory '/Users/ngift/src/buildout_demo/parts'.
Creating directory '/Users/ngift/src/buildout_demo/eggs'.
Creating directory '/Users/ngift/src/buildout_demo/develop-eggs'.
Generated script '/Users/ngift/src/buildout_demo/bin/buildout'.
查看新创建的
bin
目录,会发现有可执行文件,包括一个自定义的 Python 解释器:
$ ls -l bin
total 24
-rwxr-xr-x 1 ngift staff 362 Mar 4 22:17 buildout
-rwxr-xr-x 1 ngift staff 651 Mar 4 22:23 mypython
现在 Buildout 工具已安装,运行它并安装之前定义的 egg:
$ bin/buildout
Getting distribution for 'zc.recipe.egg'.
Got zc.recipe.egg 1.0.0.
Installing mypython.
Getting distribution for 'liten'.
Got liten 0.1.3.
Generated script '/Users/ngift/src/buildout_demo/bin/liten'.
Generated interpreter '/Users/ngift/src/buildout_demo/bin/mypython'.
查看
bin
目录:
$ ls -l bin
total 24
-rwxr-xr-x 1 ngift staff 362 Mar 4 22:17 buildout
-rwxr-xr-x 1 ngift staff 258 Mar 4 22:23 liten
-rwxr-xr-x 1 ngift staff 651 Mar 4 22:23 mypython
运行自定义 Python 解释器并导入
liten
模块:
$ bin/mypython
>>> import liten
由于
liten
是使用入口点创建的,它会在本地 Buildout 的
bin
目录中自动安装一个控制台脚本。运行该脚本:
$ bin/liten
Usage: liten [starting directory] [options]
A command - line tool for detecting duplicates using md5 checksums.
Options:
--version show program's version number and exit
-h, --help show this help message and exit
-c, --config Path to read in config file
-s SIZE, --size=SIZE File Size Example: 10bytes, 10KB, 10MB,10GB,10TB, or
plain number defaults to MB (1 = 1MB)
-q, --quiet Suppresses all STDOUT.
-r REPORT, --report=REPORT
Path to store duplication report. Default CWD
-t, --test Runs doctest.
Buildout 的强大之处还体现在它对运行目录有完全的“控制”。每次运行 Buildout 时,它都会读取
buildout.cfg
文件以获取指令。如果从
buildout.cfg
文件中移除列出的 egg,就会有效地移除命令行工具和库。例如,将
buildout.cfg
文件修改为:
[buildout]
parts =
然后使用
-N
选项重新运行 Buildout(
-N
选项只会修改已更改的文件,默认情况下,Buildout 每次运行时都会从头开始重建所有内容):
$ bin/buildout -N
Uninstalling mypython.
查看
bin
目录,会发现解释器和命令行工具已被移除,只剩下 Buildout 命令行工具:
$ ls -l bin/
total 8
-rwxr-xr-x 1 ngift staff 362 Mar 4 22:17 buildout
查看
eggs
目录,会发现 egg 已安装但未激活,由于没有解释器,无法运行它:
$ ls -l eggs
total 640
drwxr-xr-x 7 ngift staff 238 Mar 4 22:54 liten-0.1.3-py2.5.egg
-rw-r--r-- 1 ngift staff 324858 Feb 16 23:47 setuptools-0.6c8-py2.5.egg
drwxr-xr-x 5 ngift staff 170 Mar 4 22:17 zc.buildout-1.0.0-py2.5.egg
drwxr-xr-x 4 ngift staff 136 Mar 4 22:23 zc.recipe.egg-1.0.0-py2.5.egg
使用 Buildout 进行开发
在了解了创建和销毁 Buildout 控制环境的简单示例后,我们可以进一步创建一个 Buildout 控制的开发环境。
一个常见的场景是,开发者在版本控制系统中处理一个单独的包。开发者将项目检出到顶级
src
目录,然后在
src
目录中按照前面描述的方法运行 Buildout,并使用如下示例配置文件:
[buildout]
develop = .
parts = test
[python]
recipe = zc.recipe.egg
interpreter = python
eggs = ${config:mypkgs}
[scripts]
recipe = zc.recipe.egg:scripts
eggs = ${config:mypkgs}
[test]
recipe = zc.recipe.testrunner
eggs = ${config:mypkgs}
virtualenv 虚拟环境工具
根据 Python 包索引页面的文档,“virtualenv 是一个创建隔离 Python 环境的工具”。它主要解决的问题是避免包冲突。通常,一个工具可能需要某个包的特定版本,而另一个工具可能需要该包的不同版本,这可能会导致生产环境中的 Web 应用程序出现问题。此外,开发者可能没有对全局
site-packages
目录的写入权限,这时可以使用 virtualenv 创建一个与系统 Python 隔离的虚拟环境。
virtualenv 还可以通过允许开发者用自定义环境预填充虚拟环境来“引导”虚拟环境,这与 Buildout 类似,但 Buildout 使用声明式配置文件。需要注意的是,Buildout 和 virtualenv 都广泛使用
setuptools
,其当前维护者是 Phillip J. Eby。
使用 virtualenv
使用
easy_install
安装 virtualenv 是最直接的方法:
sudo easy_install virtualenv
如果只使用一个版本的 Python,这种方法效果很好。但如果你的机器上安装了多个版本的 Python(如 Python 2.4、Python 2.5、Python 2.6 和 Python 3000),且它们共享同一个主
bin
目录(如
/usr/bin
),则可以采用以下替代方法,因为同一脚本目录中一次只能安装一个 virtualenv 脚本。
创建多个适用于不同 Python 版本的 virtualenv 脚本的步骤如下:
1. 下载最新版本的 virtualenv:
curl http://svn.colorstudy.com/virtualenv/trunk/virtualenv.py > virtualenv.py
-
将
virtualenv.py复制到/usr/local/bin:
sudo cp virtualenv.py /usr/local/bin/virtualenv.py
- 在 Bash 或 zsh 中创建别名:
alias virtualenv-py24="/usr/bin/python2.4 /usr/local/bin/virtualenv.py"
alias virtualenv-py25="/usr/bin/python2.5 /usr/local/bin/virtualenv.py"
alias virtualenv-py26="/usr/bin/python2.6 /usr/local/bin/virtualenv.py"
有了多脚本环境后,就可以为需要处理的每个 Python 版本创建虚拟环境。例如,创建 Python 2.4 虚拟环境:
virtualenv-py24 myenv24
通过以上介绍,我们详细了解了 Python 包管理的多种方式,包括入口点的使用、向 Python 包索引注册包、Distutils、Buildout 和 virtualenv 等工具。掌握这些包管理技能,将有助于开发者更高效地进行 Python 开发。
Python 包管理全解析(续)
各种包管理工具对比
为了更清晰地了解不同包管理工具的特点和适用场景,下面通过一个表格进行对比:
| 工具名称 | 主要功能 | 优点 | 缺点 | 适用场景 |
| — | — | — | — | — |
| Distutils | 创建和分发 Python 包 | 是 Python 标准库的一部分,无需额外安装 | 功能相对较少,缺乏依赖管理等高级功能 | 简单的包分发,对依赖管理要求不高的场景 |
| setuptools | 增强版的 Distutils,提供更多功能 | 支持依赖管理、入口点等高级特性 | 可能会引入额外的依赖 | 大多数 Python 项目的包管理 |
| Buildout | 管理应用的构建和部署,可创建隔离环境 | 可重复构建,能精确控制依赖和环境 | 配置文件相对复杂 | 复杂应用的部署,需要隔离环境的项目 |
| virtualenv | 创建隔离的 Python 环境 | 解决包冲突问题,方便不同项目使用不同版本的包 | 不直接处理包的分发和安装 | 开发环境中避免包冲突,多个项目使用不同 Python 版本 |
包管理流程总结
下面是一个使用 mermaid 格式的流程图,展示了从创建代码到最终部署的包管理流程:
graph LR
A[创建代码] --> B[编写 setup.py 文件]
B --> C{选择包管理工具}
C -->|Distutils| D[创建源分发或二进制分发]
C -->|setuptools| E[向 PyPI 注册包]
C -->|Buildout| F[创建 buildout.cfg 文件并运行]
C -->|virtualenv| G[创建虚拟环境]
D --> H[安装包]
E --> H
F --> H
G --> H
常见问题及解决方法
在 Python 包管理过程中,可能会遇到一些常见问题,下面是一些问题及解决方法的总结:
1.
包冲突问题
-
问题描述
:不同工具或项目需要同一个包的不同版本,导致冲突。
-
解决方法
:使用 virtualenv 创建隔离的 Python 环境,每个环境可以安装不同版本的包。
2.
依赖安装失败
-
问题描述
:在安装包时,由于网络问题或依赖不兼容等原因,导致依赖安装失败。
-
解决方法
:检查网络连接,尝试手动安装依赖,或者更新 setuptools 等包管理工具。
3.
Buildout 配置错误
-
问题描述
:Buildout 的 buildout.cfg 文件配置错误,导致 Buildout 运行失败。
-
解决方法
:仔细检查 buildout.cfg 文件的语法和配置项,参考官方文档进行修正。
最佳实践建议
为了更好地进行 Python 包管理,以下是一些最佳实践建议:
1.
使用 virtualenv
:在开发项目时,始终使用 virtualenv 创建隔离的 Python 环境,避免包冲突。
2.
及时更新包
:定期更新项目中使用的包,以获取最新的功能和安全补丁。
3.
详细记录依赖
:在项目的文档或配置文件中详细记录项目的依赖,方便其他开发者进行环境搭建。
4.
测试包兼容性
:在更新包或引入新的依赖时,进行充分的测试,确保项目的兼容性。
总结
Python 包管理是 Python 开发中不可或缺的一部分,合理使用各种包管理工具可以提高开发效率、避免包冲突等问题。本文详细介绍了入口点与脚本安装、向 Python 包索引注册包、Distutils、Buildout 和 virtualenv 等包管理工具的使用方法,通过对比和总结,希望能帮助开发者更好地掌握 Python 包管理技能,在实际开发中更加得心应手。
通过不断学习和实践,相信你会在 Python 包管理方面积累更多的经验,为 Python 项目的开发和部署提供有力的支持。
超级会员免费看

被折叠的 条评论
为什么被折叠?



