20201223_149_包的本质和init文件_批量导入_包内引用

3.4 导入包的本质

导入包的本质其实是“导入了包的__init__.py”文件。也就是说,”import pack1”意味着执行了包 pack1 下面的__init__.py 文件。 这样,可以在__init__.py 中批量导入我们需要的模块,而不再需要一个个导入。

【例1】
包 a 的 __init__.py 定义中,如下图:
在这里插入图片描述
所以实际上导入 a 包的时候就是批量导入了 turtle 和 math 两个包。
并且,再单独导入 math 对比查看 id:

import a
import math


print(id(math))
print(id(a.math))

运行结果:
在这里插入图片描述
分析:
由此可见,两个math是同一个对象。实际是首先在 import a 时导入了 math 模块,形成了对象, 并记为 a.math,import math 之后不过是再又把 a.math 引用的对象又引用给 math。

__init__.py 的三个核心作用:

  1. 作为包的标识,不能删除;
  2. 用来实现模糊导入;
  3. 导入包实质是执行__init__.py 文件,可以在__init__.py 文件中做这个包的初始化、以及需要统一执行代码、批量导入。

【例2】测试包的__init__.py 文件的用法
a 包下的__init__.py 文件内容:

import turtle
import math


print('导入a包')

b 包下的 module_B1.py 文件中导入 a 包,代码如下:

import a

print(a.math.pi)

运行结果:
在这里插入图片描述
分析:
可以看到,在 a 包定义中导入的 math 模块在 b 包的 module_B!.py 中运行后,将 math 识别为 a 包的子包了。

注1:如上测试我们可以看出 python 的设计者非常巧妙的通过__init__.py 文件将包转成了模块的操作。因此,可以说“包的本质还是模块”。
注2:实际上可以在__init__.py 文件中定义类、函数,但为了保证结构的统一性(类和函数的定义一般在包内其他py文件中定义),一般不这样操作,还是仅将__init__.py 文件用于批量导入模块。

3.5 用*导入包

import * 这样的语句理论上是希望文件系统找出包中所有的子模块,然后导入它们。这可能会花长时间等。Python 解决方案是提供一个明确的包索引。

这个索引由 __init__.py 定义 __all__ 变量,该变量为一列表,如上例 a 包下的 __init__.py 中,可定义:

__all__ = ['module_A1', 'module_A2']

这意味着, from a import * 会从对应的包中导入以上 module_A1 和 module_A2 两个子模块。
即由 __all__ 变量定义的列表来决定 from xx包 import * 是导入哪些子模块。

注意:
尽管提供 import * 的方法,仍不建议在生产代码中使用这种写法。

3.6 包内引用

如果是子包内的引用,可以按相对位置引入子模块。以 aa 包下的 module_AA1 中导入 a 包下内容为例:
包的结果如下图:
在这里插入图片描述
包内引用代码为:

from .. import module_A1  #..表示上级目录
.表示同级目录
from . import module_AA2  #.表示同级目录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值