包,Package,是一种Python模块的集合,从文件组织形式上看,包就是一个文件夹,里面放着各类模块(.py文件),也能够有子文件夹(子包)。包名构建了一个Python模块的命名空间。好比,模块名A.B
表示A
包中名为B
的子模块。这种使用加点的模块名可让你写的软件包里面的模块名称和其它软件包里面的模块名称同样,但又不相互冲突。python
举个栗子,咱们要设计一个处理图片的模块集合(一个包)。咱们知道,图片有多种不一样的文件格式,通常它们以不一样的扩展名来识别,好比.jpg
,.png
,.gif
等等。为了读写不一样格式的图片,你须要对每一种格式创建一个对应的模块进行处理,为了支持更多的图片格式,你就要增长更多对应的模块。对于图片你可能还有更多的处理,好比,改变色彩,裁剪,旋转等等,为了实现这些功能,你又要写更多的模块。这样下来,你的包的结构以文件系统的形式表示以下:spa
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模块。设计
前面说了,包的目录中必须包含一个__init__.py
文件,它能够是空文件,也能够写包初始化相关的代码,或者定义__all__
变量。code
__all__
变量是一个列表,它列举了这个包包含的子模块的名称。当from package import *
语句执行时,会把这个模块名称列表里面的模块名称导入。因此说__all__
是一个包的显示索引。若是你以为从包中导入*
的操做不必被使用,也能够不定义__all__
这个变量。orm
例如,文件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
,但能够取个别名。图片处理
导入包的方法和导入模块的方法同样:rem
import image
在程序中引用colors
子模块时:
image.process.colors(...)
接下来,看看咱们如何导入一个包中某单个模块:
import image.process.colors
这样就加载了子模块image.process.colors
,在程序中使用时必须使用它的全名,而不是简单的colors
。
若是想使用colors
这个名字,就用这种导入语句:
from image.process import colors
当包含有子包时(与例子中的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应用程序的主模块的模块必须用绝对导入。也就是说被执行的主程序里面不能包含相对导入。这一点很重要,切记!