包,Package,是一种Python模块的集合,从文件组织形式上看,包就是一个文件夹,里面放着各种模块(.py文件),也可以有子文件夹(子包)。包名构建了一个Python模块的命名空间。比如,模块名A.B
表示A
包中名为B
的子模块。这种使用加点的模块名可以让你写的软件包里面的模块名称和其它软件包里面的模块名称一样,但又不相互冲突。
举个栗子,我们要设计一个处理图片的模块集合(一个包)。我们知道,图片有多种不同的文件格式,一般它们以不同的扩展名来识别,比如.jpg
,.png
,.gif
等等。为了读写不同格式的图片,你需要对每一种格式建立一个对应的模块进行处理,为了支持更多的图片格式,你就要增加更多对应的模块。对于图片你可能还有更多的处理,比如,改变色彩,裁剪,旋转等等,为了实现这些功能,你又要写更多的模块。这样下来,你的包的结构以文件系统的形式表示如下:
image # 顶级包
├── __init__.py # 初始化image包
├── formats # 图片格式的子包
│ ├── gif_read.py
│ ├── gif_write.py
│ ├── __init__.py
│ ├── jpg_read.py
│ ├── jpg_write.py
│ ├── png_read.py
│ └── png_write.py
└── process # 图片处理的子包
├── colors.py
├── crop.py
├── __init__.py
└── rotate.py
为了让目录成为Python的包,目录中必须含有一个__init__.py
文件,它可以是空文件但不能不存在。这样做的目的是为了仿照具有通用名称的目录无意中隐藏了在模块搜索路径排在后面的有效模块。比如,你当前目录下有个time
目录是放程序资源的,它里面没有__init__.py
文件就是一个普通的目录。如果Python不要求包目录下必须含有__init__.py
文件,它就会隐藏Python系统的time模块。
__all__变量
前面说了,包的目录中必须包含一个__init__.py
文件,它可以是空文件,也可以写包初始化相关的代码,或者定义__all__
变量。
__all__
变量是一个列表,它列举了这个包包含的子模块的名称。当from package import *
语句执行时,会把这个模块名称列表里面的模块名称导入。所以说__all__
是一个包的显示索引。如果你觉得从包中导入*
的操作没必要被使用,也可以不定义__all__
这个变量。
例如,文件image/process/init.py可以包含以下代码:
__all__ = ['colors', 'crop', 'rotate']
定义了__all__
之后,from image.process import *
就会把colors
,crop
,rotate
导入到当前命名空间。
实际写代码的实践中,import *
的做法是严格被禁止的,它容易造成包中模块名与当前命名空间的名称冲突。
更推荐的方法是from package import submodule
或from package import submodule as alias_for_submodule
。当然,如果两个包中有同名的submodule,就不能同时使用from package import submodule
,但可以取个别名。
导入Python包或Python子模块
导入包的方法和导入模块的方法一样:
import image
在程序中引用colors
子模块时:
image.process.colors(...)
接下来,看看我们如何导入一个包中某单个模块:
import image.process.colors
这样就加载了子模块image.process.colors
,在程序中使用时必须使用它的全名,而不是简单的colors
。
如果想使用colors
这个名字,就用这种导入语句:
from image.process import colors
Python子包参考
当包含有子包时(与例子中的image包类似),我们可以使用绝对导入来引用兄弟包的子模块。比如,如果模块 image.process.crop 需要使用 image.formats 包中的 jpg_read 模块时,它可以使用 from image.formats import jpg_read
。
我们也可以使用 from module import name
的形式相对导入。这种导入使用前导点.
来指示相对导入中涉及的当前包
和父包
。比如,在 crop 模块中,你可以使用:
from . import colors
from .. import formats
from ..formats import jpg_read
请主要,相对导入是基于当前模块的名字进行导入的。由于主模块(即被python 执行的那个.py文件)的名称总是"__main__"
,因此用作Python应用程序的主模块的模块必须用绝对导入。也就是说被执行的主程序里面不能包含相对导入。这一点很重要,切记!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。