Python - 模块包

包导入示例

下列三个文件分别位于目录dir1 以及 dir1 的子目录 dir2中,这些文件的路径名在注释中给出:

# dir1\__init__.py
print('dir1 init')
x = 1

# dir1\dir2\__init__.py
print('dir2 init')
y = 2

# dir1\dir2\mod.py
print('in mod.py')
z = 3

这里,dir1 要么是我们当前工作所在目录的(也就是主目录)的子目录,要么就是位于模块搜索路径中(实际就是sys.path)的一个目录的子目录。无论哪一种,dir1 的容器都不需要_init_.py 文件。

当Python 向下搜索路径的时候,import 语句会在目录首次遍历时执行该目录的初始化文件。这里使用print 语句来跟踪它们的执行:

>>> import dir1.dir2.mod                                              
dir1 init
dir2 init
in mod.py
>>> import dir1.dir2.mod 
>>> 

就像模块文件一样,任何已导入的目录也可以传递给reload,来强制该项目重新执行。就像这里展示的那样,reload 可以接受点号路径名称来重新载入嵌套的目录和文件:

>>> from importlib import reload
>>> reload(dir1) 
dir1 init
<module 'dir1' from 'E:\\PyProject\\dir0\\dir1\\__init__.py'>
>>> reload(dir1.dir2) 
dir2 init
<module 'dir1.dir2' from 'E:\\PyProject\\dir0\\dir1\\dir2\\__init__.py'>
>>> 

一旦导入后,import 语句内的路径会变成脚本中共的一条嵌套对象路径。在这里mod 是一个嵌套在dir2 中的子对象,而dir2又嵌套在dir1 中:

>>> dir1
<module 'dir1' from 'E:\\PyProject\\dir0\\dir1\\__init__.py'>
>>> dir2   # 无法直接方法
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'dir2' is not defined. Did you mean: 'dir1'?
>>> dir1.dir2
<module 'dir1.dir2' from 'E:\\PyProject\\dir0\\dir1\\dir2\\__init__.py'>
>>> dir1.dir2.mod
<module 'dir1.dir2.mod' from 'E:\\PyProject\\dir0\\dir1\\dir2\\mod.py'>

实际上,路径中的每个目录名称都会变成赋值了模块对象的变量,而该模块对象的命名空间则是由该目录内的_init_.py 文件中共所有赋值语句进行初始化的。dir1.x 引用了在dir1._init_.py 中赋值的x 变量,mod.z 则引用了在mod.py 内赋值的变量z:

>>> dir1.x
1
>>> dir1.dir2.y 
2
>>> dir1.dir2.mod.z
3
>>> dir1.dir2.mod.y  # 不能访问y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'dir1.dir2.mod' has no attribute 'y'
>>>

包的from 语句 vs 包的 import 语句

当import 语句和 包一起使用时可能有些不便,因为必须经常在程序中重新输入路径。例如,上一节的例子中,每次要得到z时,就得从dir1 开始重新输入完整得路径,并且每次都要重新执行整个路径。如果你想要尝试直接读取dir2 或 mod ,就会得到一个错误:

>>> dir2.mod
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'dir2' is not defined. Did you mean: 'dir1'?
>>> mod.z
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'mod' is not defined

因此,我们可以 让包使用from语句,来避免每次读取时都要重新输入路径,通常这样比较方便。也许更重要得是,如果你重新改变目录结构,那么from语句只需要在程序代码中共更新一次路径,import 则需要修改很多地方,它提供了一个完整路径较短得同义词,并在出现多个同名模块得时候充当重新命名得工具:

>>> from dir1.dir2 import mod                                         
dir1 init
dir2 init
in mod.py
>>> mod.z
3   
>>> import dir1.dir2.mod as mod
>>> mod.z
3   
>>> 

posted @ 2024-04-30 21:45  chuangzhou  阅读(3)  评论(0编辑  收藏  举报