理解包
你首先需要理解的是Python没有一个默认的包管理设施。事实上,包的概念在Python中是相当弱的。
可能你已经知道,Python代码被组织为模块。
一个模块可能由包含一个函数的单一文件组成,也可能由包含多个模块的目录组成。
包和模块的区别非常小,并且每个模块都能被理解为包。
那么包和模块的区别到底是什么(如果有的话)?为了明白这个,你首先应该明白Python是如何查找模块的。
如同别的编程环境一样,Python中的一些函数和类(例如str,len,Exception等)在全局(叫做内置函数)都是可用的。
别的就需要通过手动 import
进来。例如:
- >>> import os
- >>> from os.path import basename, dirname
这个包一定存在你的机子上,这样才能被import语句导入。但Python是如何知道这些模块的位置呢?
这些位置信息在你安装Python虚拟机时就被自动设置好了,并且依赖于你的目标平台。
包的路径可以在sys.path中查询。下面是在我的笔记本上的结果,运行环境是Ubuntu 11.10。
- >>> import sys
- >>> print sys.path
- ['',
- '/usr/lib/python2.7',
- '/usr/lib/python2.7/plat-linux2',
- '/usr/lib/python2.7/lib-tk',
- '/usr/lib/python2.7/lib-old',
- '/usr/lib/python2.7/lib-dynload',
- '/usr/local/lib/python2.7/dist-packages',
- '/usr/lib/python2.7/dist-packages',
- '/usr/lib/python2.7/dist-packages/PIL',
- '/usr/lib/python2.7/dist-packages/gst-0.10',
- '/usr/lib/python2.7/dist-packages/gtk-2.0',
- '/usr/lib/pymodules/python2.7',
- '/usr/lib/python2.7/dist-packages/ubuntu-sso-client',
- '/usr/lib/python2.7/dist-packages/ubuntuone-client',
- '/usr/lib/python2.7/dist-packages/ubuntuone-control-panel',
- '/usr/lib/python2.7/dist-packages/ubuntuone-couch',
- '/usr/lib/python2.7/dist-packages/ubuntuone-installer',
- '/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol']
这里给出了Python搜索包的路径。它将从最上面开始找,直到找到一个名字相符的。
这表明如果两个不同的路径分别包含了两个具有相同名字的包,搜索将在找到第一个名字的时候停止,然后将永远不会往下查找。
正如你所猜的,包搜索路径很容易被劫持,为了确保Python首先载入你的包,所需做的如下:
- >>> sys.path.insert(0, '/path/to/my/packages')
尽管这个方法在很多情况下都很好用,但一定要小心不要滥用。 只有当必要时再使用!不要滥用!
site
模块控制包的搜索路径。当Python虚拟机初始化时它会自动被导入。如果你想了解更多信息,请看 官方文档 。
PYTHONPATH变量
PYTHONPATH
是一个用来增加默认包搜索目录的环境变量。可以认为它是对于Python的一个特殊的 PATH
变量。
它仅仅是一个通过 :
分割,包含Python模块目录的列表(并不是类似于 sys.path
的Python list)。
它可能就类似下面这样:
- export PYTHONPATH=/path/to/some/directory:/path/to/another/directory:/path/to/yet/another/directory
有时候你可能并不想覆盖掉现存的 PYTHONPATH
,而仅仅是希望添加新目录到头部或尾部。
- export PYTHONPATH=$PYTHONPATH:/path/to/some/directory # Append
- export PYTHONPATH=/path/to/some/directory:$PYTHONPATH # Prepend
PYTHONPATH
, sys.path.insert
这些方法并非完美,我们最好也不要用这些方法。
使用它们,你可能可以解决本地的开发环境问题,但它在别的环境下也许并不适用。
有很多种方法可以达到这个效果,在下面我将一一阐述。
我们现在明白的Python如何找到安装的包路径,现在让我们回到开始那个问题。
模块和包的区别到底是什么?包是一个模块或模块/子模块的集合,一般情况下被压缩到一个压缩包中。
其中包含1)依赖信息 2)将文件拷贝到标准的包搜索路径的指令。3)编译指令(如果在安装前代码必须被编译的话)。
就这些东西!