一个python文件就是一个模块,使用独立的命名空间,但实际使用过程中单单用模块来定义python功能显然还不够。因为一个大型的系统几千上万个模块是很正常的事情,如果都聚集在一起显然不好管理并且有命名冲突的可能,因此python中也出现了一个包的概念。

一、python中的包介绍

      包是通过使用“点模块名称”创建Python模块命名空间的一种方法。列如,模块名称 A.B 表示一个在名为 A的包下的名为B的子模块。就像使用模块让不同模块的作者无需担心彼此全局变量名称(冲突)一样,点模块名称让多模块包的作者无需担心彼此的模块名称(冲突)。模块包在文件系统中的表示就是一系列目录的集合,通过目录的层级结构形成模块包的层级结构,最终的模块文件就位于最后的目录中。比如定义一个简单的模块在包pkg下,那么执行如下步骤:

1、在D:\temp目录下建立一个目录,名称是pkg

2、在pkg下建立一个__init__.py的模块,内容为空即可

3、在pkg目录下建立一个python模块module_3.py,内容如下:

# -*- encoding:utf-8 -*-'''pkg.module_3.py模块的内容''' print("Hello World") def func1():print("This is funciton one")

      注意第2步,必须要在每一个包目录下建立一个__init__.py的模块,这个是python的规定,用来告诉python解释器将该目录当成一个内容包,即该目录是一个包,里面包含了python模块的。这个是必须的,如果不指定,则我们在python的交互模式下导入module_3.py这个模块时会报如下错误:

>>> import pkg.module_3Traceback (most recent call last):File "<stdin>", line 1, in <module>ImportError: No module named pkg.module_3

      因此包目录下的__init__.py模块是必须的,但内容是可选的,可以为空内容,也可以写一些代码或作其他用途。PVM在导入某个包下的模块时会先导入这个包下的__init__.py模块,比如我们将__init__.py模块的内容指定如下:

print("This is __init__ module")

      然后在交互模式下重新导入这个包,则效果如下:

>>> import pkg.module_3This is __init__ moduleHello World>>>

      可见,PVM首先加载的是__init__.py模块,然后才是找该目录下的其他模块并进行加载。

二、python中的模块搜索路径

      在一个模块被导入时,PVM会在后台从一系列路径中搜索该模块,其搜索过程如下:

1、在当前目录下搜索该模块;

2、在环境变量PYTHONPATH中指定的路径列表中依次搜索;

3、在python安装路径中搜索

      事实上,PVM通过变量sys.path中包含的路径来搜索,这个变量里面包含的路径列表就是上面提到的这些路径信息,我们可以打印看下sys.pth都包含些哪些路径:

>>> import sys>>> print(sys.path)['', 'C:\\Windows\\system32\\python27.zip', 'D:\\tools\\Python27\\DLLs', 'D:\\tools\\Python27\\lib', 'D:\\tools\\Python27\\lib\\plat-win', 'D:\\tools\\Python27\\lib\\lib-tk', 'D:\\tools\\Python27', 'D:\\tools\\Python27\\lib\\site-packages','D:\\tools\\Python27\\lib\\site-packages\\wx-2.8-msw-unicode']

      不同的机器上显示的路径信息可能不一样,但至少都包含上面提到的3点。知道了这个路径搜索规律后,我们就可以很方便的将某些目录动态的增加到搜索路径中去,比如在E盘下建立一个python模块module_4.py,内容如下:

print("Hello world")print 2 ** 2

      然后在交互模式下执行导入:

>>> import module_4Traceback (most recent call last):File "<stdin>", line 1, in <module>ImportError: No module named module_4

      报错是预料中的,因为E盘并不在python模块的搜索路径中,然后我们动态的增加这个路径到搜索模块中,再执行导入:

>>> sys.path.append("E:\\")>>> print(sys.path)['', 'C:\\Windows\\system32\\python27.zip', 'D:\\tools\\Python27\\DLLs', 'D:\\tools\\Python27\\lib', 'D:\\tools\\Python27\\lib\\plat-win', 'D:\\tools\\Python27\\lib\\lib-tk', 'D:\\tools\\Python27', 'D:\\tools\\Python27\\lib\\site-packages','D:\\tools\\Python27\\lib\\site-packages\\wx-2.8-msw-unicode', 'E:\\']>>> import module_4Hello world4

      首先是在sys.path中增加了E盘根目录作为搜索路径,随后的打印中可以看到确实已经被添加到sys.path中去了,然后再执行导入就会正常导入模块并执行模块中的语句了。当然,我们通过交互模式新增加的搜索路径也仅仅是在当前交互模式下有效,一旦退出了那么就就失效了。因此,我们可以根据搜索路径规则的第2步中说的来设置PYTHONPATH环境变量就可以满足不同使用情况下都可以找到模块了。



转载于:https://blog.51cto.com/mannu/1686880