解析Python编程中的包结构
假设你想设计一个模块集(也就是一个“包”)来统一处理声音文件和声音数据。通常由它们的扩展有不同的声音格式,例如:WAV,AIFF,AU),所以你可能需要创建和维护一个不断增长的各种文件格式之间的转换的模块集合。并且可能要执行声音数据处理(如混合,添加回声,应用平衡功能),所以你写一个永无止境的流模块来执行这些操作:模块设计的包如下:
sound/Top-levelpackage __init__.pyInitializethesoundpackage formats/Subpackageforfileformatconversions __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/Subpackageforsoundeffects __init__.py echo.py surround.py reverse.py ... filters/Subpackageforfilters __init__.py equalizer.py vocoder.py karaoke.py ...
当导入包以后,Python通过sys.path中的目录来寻找包的子目录。每一个包都必须有__init__.py文件,这样做是为了防止某些目录有一个共同的名字。在最简单的情况下,__init__.py可以只是一个空文件,但它也可以执行包的初始化代码,包括设置__all__变量,稍后介绍。我们可以从包中导入单个模块,
例如:importsound.effects.echo这会载入子模块sound.effects.echo。它必须引用全名。
sound.effects.echo.echofilter(input,output,delay=0.7,atten=4)
另外一种导入子模块的方法:fromsound.effectsimportecho这样就加载了echo子模块,没有包括包的前缀,因此它可以用作如下:
echo.echofilter(input,output,delay=0.7,atten=4)
或者可以
fromsound.effects.echoimportechofilterechofilter(input,output,delay=0.7,atten=4)
请注意,如果你使用包导入一个子模块(或子包),像一个函数,类或变量。import语句首先测试导入的对象是否包中定义,如果没有,它假定这是一个模块,并尝试加载它。如果还没有找到,则会引发一个ImportError异常。
python包管理工具大乱斗
1.distutils
distutils是python标准库的一部分,2000年发布。使用它能够进行python模块的安装和发布。
setup.py就是利用distutils的功能写成,我们可以看一个简单的setup.py的例子。
在这里可以看到关于setupt.py格式的所有详细描述:WritingtheSetupScript。
要安装一个模块到当前的python环境中,可以使用这个模块提供的setup.py文件:
pythonsetup.pyinstall下面的代码会发布一个python模块,将其打包成tar.gz或者zip压缩包:
pythonsetup.pysdist
甚至能打包成rpm或者exe安装包:
pythonsetup.pybdist_rpm pythonsetup.pybdist_wininst
2.setuptools和distribute
setuptools是一个为了增强distutils而开发的集合,2004年发布。它包含了easy_install这个工具。
ez_setup.py是setuptools的安装工具。ez就是easy的缩写。
简单的说,setuptools是一个项目的名称,是基础组件。而easy_install是这个项目中提供的工具,它依赖基础组件工作。
为了方便描述,下面文章中提到的setuptools被认为与easy_install同义。
使用setuptools可以自动下载、构建、安装和管理python模块。
例如,从PyPI上安装一个包:
easy_installSQLObject
下载一个包文件,然后安装它:
easy_installhttp://example.com/path/to/MyPackage-1.2.3.tgz
从一个.egg格式安装:
easy_install/my_downloads/OtherPackage-3.2.1-py2.3.egg
distribute是setuptools的一个分支版本。分支的原因可能是有一部分开发者认为setuptools开发太慢了。但现在,distribute又合并回了setuptools中。因此,我们可以认为它们是同一个东西。事实上,如果你查看一下easy_install的版本,会发现它本质上就是distribute。
#easy_install--version distribute0.6.28
3.Eggs
Eggs格式是setuptools引入的一种文件格式,它使用.egg扩展名,用于Python模块的安装。
setuptools可以识别这种格式。并解析它,安装它。
4.pip
注意,从此处开始,easy_install和setuptools不再同义。
pip是目前python包管理的事实标准,2008年发布。它被用作easy_install的替代品,但是它仍有大量的功能建立在setuptools组件之上。
pip希望不再使用Eggs格式(虽然它支持Eggs),而更希望采用“源码发行版”(使用pythonsetup.pysdict创建)。这可以充分利用RequirementsFileFormat提供的方便功能。
pip可以利用requirments.txt来实现在依赖的安装。在setup.py中,也存在一个install_requires表来指定依赖的安装。
pip支持git/svn/hg等流行的VCS系统,可以直接从gz或者zip压缩包安装,支持搜索包,以及指定服务器安装等等功能。
pipvseasy_install详细介绍了两者的不同。它们可以说是各占胜场,但pip明显优势更大。
5.wheel
wheel本质上是一个zip包格式,它使用.whl扩展名,用于python模块的安装,它的出现是为了替代Eggs。
wheel还提供了一个bdist_wheel作为setuptools的扩展命令,这个命令可以用来生成wheel包。
pip提供了一个wheel子命令来安装wheel包。当然,需要先安装wheel模块。
setup.cfg可以用来定义wheel打包时候的相关信息。
WheelvsEgg详细介绍了wheel和Eggs格式的区别,很显然,wheel优势明显。
PythonWheels网站展示了使用Wheels发行的python模块在PyPI上的占有率。
pypip.in也支持wheel。
6.distutils2和distlib
distutils2被设计为distutils的替代品。从2009年开发到2012年。它包含更多的功能,并希望以packaging作为名称进入python3.3成为标准库的一部分。但这个计划后来停滞了。
distlib是distutils2的部分,它为distutils2/packaging提供的低级功能增加高级API,使其便于使用。
这里介绍了distlib没有进入python3.3标准库的一些原因。
因此,可以暂时不必了解这两个工具,静观其变即可。