python基础教程:包的创建及导入

简介: 包是一种通过用“带点号的模块名”来构造 Python 模块命名空间的方法。 例如,模块名 A.B 表示 A 包中名为 B 的子模块。正如模块的使用使得不同模块的作者不必担心彼此的全局变量名称一样,使用加点的模块名可以使得 NumPy 或 Pillow 等多模块软件包的作者不必担心彼此的模块名称一样。

包是一种通过用“带点号的模块名”来构造 Python 模块命名空间的方法。 例如,模块名 A.B 表示 A 包中名为 B 的子模块。正如模块的使用使得不同模块的作者不必担心彼此的全局变量名称一样,使用加点的模块名可以使得 NumPy 或 Pillow 等多模块软件包的作者不必担心彼此的模块名称一样。

假设你想为声音文件和声音数据的统一处理,设计一个模块集合(一个“包”)。由于存在很多不同的声音文件格式(通常由它们的扩展名来识别,例如:.wav, .aiff, .au),因此为了不同文件格式间的转换,你可能需要创建和维护一个不断增长的模块集合。 你可能还想对声音数据还做很多不同的处理(例如,混声,添加回声,使用均衡器功能,创造人工立体声效果), 因此为了实现这些处理,你将另外写一个无穷尽的模块流。这是你的包的可能结构(以分层文件系统的形式表示):

      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

当导入这个包时,Python搜索 sys.path 里的目录,查找包的子目录。

The init__.py files are required to make Python treat directories containing the file as packages. This prevents directories with a common name, such as string, unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all variable, described later.

包的用户可以从包中导入单个模块,例如:

这会加载子模块 sound.effects.echo 。但引用它时必须使用它的全名。

导入子模块的另一种方法是

这也会加载子模块 echo ,并使其在没有包前缀的情况下可用,因此可以按如下方式使用:

另一种形式是直接导入所需的函数或变量:

同样,这也会加载子模块 echo,但这会使其函数 echofilter() 直接可用:

请注意,当使用 from package import item 时,item可以是包的子模块(或子包),也可以是包中定义的其他名称,如函数,类或变量。 import 语句首先测试是否在包中定义了item;如果没有,它假定它是一个模块并尝试加载它。如果找不到它,则引发 ImportError 异常。

相反,当使用 import item.subitem.subsubitem 这样的语法时,除了最后一项之外的每一项都必须是一个包;最后一项可以是模块或python包,但不能是前一项中定义的类或函数或变量。

从包中导入 *

当用户写 from sound.effects import * 会发生什么?理想情况下,人们希望这会以某种方式传递给文件系统,找到包中存在哪些子模块,并将它们全部导入。这可能需要很长时间,导入子模块可能会产生不必要的副作用,这种副作用只有在显式导入子模块时才会发生。

唯一的解决方案是让包作者提供一个包的显式索引。import 语句使用下面的规范:如果一个包的 init__.py 代码定义了一个名为 __all 的列表,它会被视为在遇到 from package import 时应该导入的模块名列表。在发布该包的新版本时,包作者可以决定是否让此列表保持更新。包作者如果认为从他们的包中导入 的操作没有必要被使用,也可以决定不支持此列表。例如,文件 sound/effects/__init__.py 可以包含以下代码:

这意味着 from sound.effects import * 将导入 sound 包的三个命名子模块。

如果没有定义 __all__,from sound.effects import * 语句 不 会从包 sound.effects 中导入所有子模块到当前命名空间;它只确保导入了包 sound.effects (可能运行任何在 __init__.py 中的初始化代码),然后导入包中定义的任何名称。这包括 __init__.py` 定义的任何名称(以及显式加载的子模块)。它还包括由之前的 import 语句显式加载的包的任何子模块。思考下面的代码:

import sound.effects.surround
from sound.effects import *

在这个例子中, echo 和 surround 模块是在执行 from...import 语句时导入到当前命名空间中的,因为它们定义在 sound.effects 包中。(这在定义了 all 时也有效。)

虽然某些模块被设计为在使用 import * 时只导出遵循某些模式的名称,但在生产代码中它仍然被认为是不好的做法。

请记住,使用 from Package import specific_submodule 没有任何问题!实际上,除非导入模块需要使用来自不同包的同名子模块,否则这是推荐的表示法。

子包参考

当包被构造成子包时(与示例中的 sound 包一样),你可以使用绝对导入来引用兄弟包的子模块。例如,如果模块 sound.filters.vocoder 需要在 sound.effects 包中使用 echo 模块,它可以使用 from sound.effects import echo 。

你还可以使用import语句的 from module import name 形式编写相对导入。这些导入使用前导点来指示相对导入中涉及的当前包和父包。例如,从 surround 模块,你可以使用:

from .. import formats
from ..filters import equalizer

请注意,相对导入是基于当前模块的名称进行导入的。由于主模块的名称总是 "__main__" ,因此用作Python应用程序主模块的模块必须始终使用绝对导入。

多个目录中的包
包支持另一个特殊属性, path 。它被初始化为一个列表,其中包含在执行该文件中的代码之前保存包的文件 __init__.py 的目录的名称。这个变量可以修改;这样做会影响将来对包中包含的模块和子包的搜索。

虽然通常不需要此功能,但它可用于扩展程序包中的模块集。

脚注

[1] 实际上,函数定义也是“被执行”的“语句”;模块级函数定义的执行在模块的全局符号表中输入该函数名。

相关文章
|
7天前
|
Python
SciPy 教程 之 Scipy 显著性检验 3
本教程介绍Scipy显著性检验,包括其基本概念、原理及应用。显著性检验用于判断样本与总体假设间的差异是否显著,是统计学中的重要工具。Scipy通过`scipy.stats`模块提供了相关功能,支持双边检验等方法。
13 1
|
9天前
|
机器学习/深度学习 Python
SciPy 教程 之 SciPy 插值 2
SciPy插值教程:介绍插值概念及其在数值分析中的应用,特别是在处理数据缺失时的插补和平滑数据集。SciPy的`scipy.interpolate`模块提供了强大的插值功能,如一维插值和样条插值。通过`UnivariateSpline()`函数,可以轻松实现单变量插值,示例代码展示了如何对非线性点进行插值计算。
11 3
|
12天前
|
机器学习/深度学习 数据处理 Python
SciPy 教程 之 SciPy 空间数据 4
本教程介绍了SciPy的空间数据处理功能,主要通过scipy.spatial模块实现。内容涵盖空间数据的基本概念、距离矩阵的定义及其在生物信息学中的应用,以及如何计算欧几里得距离。示例代码展示了如何使用SciPy计算两点间的欧几里得距离。
27 5
|
11天前
|
机器学习/深度学习 Python
SciPy 教程 之 SciPy 空间数据 6
本教程介绍了SciPy处理空间数据的方法,包括使用scipy.spatial模块进行点位置判断、最近点计算等内容。还详细讲解了距离矩阵的概念及其应用,如在生物信息学中表示蛋白质结构等。最后,通过实例演示了如何计算两点间的余弦距离。
22 3
|
10天前
|
机器学习/深度学习 数据处理 Python
SciPy 教程 之 SciPy 空间数据 7
本教程介绍了SciPy的空间数据处理功能,涵盖如何使用`scipy.spatial`模块进行点的位置判断、最近点计算等操作。还详细解释了距离矩阵的概念及其在生物信息学中的应用,以及汉明距离的定义和计算方法。示例代码展示了如何计算两个点之间的汉明距离。
18 1
|
14天前
|
Python
SciPy 教程 之 SciPy 图结构 7
《SciPy 教程 之 SciPy 图结构 7》介绍了 SciPy 中处理图结构的方法。图是由节点和边组成的集合,用于表示对象及其之间的关系。scipy.sparse.csgraph 模块提供了多种图处理功能,如 `breadth_first_order()` 方法可按广度优先顺序遍历图。示例代码展示了如何使用该方法从给定的邻接矩阵中获取广度优先遍历的顺序。
24 2
|
15天前
|
算法 Python
SciPy 教程 之 SciPy 图结构 5
SciPy 图结构教程,介绍图的基本概念和SciPy中处理图结构的模块scipy.sparse.csgraph。重点讲解贝尔曼-福特算法,用于求解任意两点间最短路径,支持有向图和负权边。通过示例演示如何使用bellman_ford()方法计算最短路径。
26 3
|
15天前
|
缓存 测试技术 Apache
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
31 1
|
8天前
|
机器学习/深度学习 数据处理 Python
SciPy 教程 之 SciPy 插值 3
本教程介绍了SciPy中的插值方法,包括什么是插值及其在数据处理和机器学习中的应用。通过 `scipy.interpolate` 模块,特别是 `Rbf()` 函数,展示了如何实现径向基函数插值,以平滑数据集中的离散点。示例代码演示了如何使用 `Rbf()` 函数进行插值计算。
14 0
|
8天前
|
Python
SciPy 教程 之 Scipy 显著性检验 1
本教程介绍Scipy显著性检验,包括统计假设、零假设和备择假设等概念,以及如何使用scipy.stats模块进行显著性检验,以判断样本与总体假设间是否存在显著差异。
13 0