第二模块第21章模块 包
egon老师知乎文章地址:
https://www.luffycity.com/play/20704
1. 什么是包?
包就是一个包含__init__.py文件的文件夹
包的本质是模块的一种形式
2. 为何要有包?
包的本质是模块的一种形式, 包会被当作模块被导入
import mm做的三件事:
1. 产生一个名称空间
2. 运行包下的__init__.py文件, 将运行过程中产生的名字都丢到名称空间中去
3. 在当前执行文件的名称空间中拿到一个名字, 该名字指向1的名称空间
强调:
1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块
3. 包的使用
要想调用到包中的功能, 需要将包中包含的各个py文件导入到__init__.py文件中, 导入方式如下:
1. 绝对导入(站在包设计者的角度)
以包的文件夹作为起始进行导入
示例:
文件路径:
包''bb和"执行文件"run包"在同一路径下, 'run包'中可以使用以下代码调用bb包:
# 方式一
import bb bb.f1() bb.f2()
'''
结果:
这是m1
这是m2
'''
# 方式二 from bb import f1, f2 f1() f2() ''' 结果: 这是m1 这是m2 '''
如果包bb与执行文件不在同一路径下, 则调用方法如下:
# 方式一 import sys sys.path.append(r'F:\python全栈开发\python\day21\aa') import bb bb.f1() bb.f2() ''' 结果: 这是m1 这是m2 '''
# 方式二 import sys sys.path.append(r'F:\python全栈开发\python\day21\aa') from bb import f1, f2 f1() f2() ''' 结果: 这是m1 这是m2 '''
注意: 环境变量是以执行文件为准的, 所有被导入的模块或后续的其他文件引用的sys.path都是参照执行文件的.
强调:
1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如import 顶级包.子包.子模块,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包, 模块,函数,类(它们都可以用点的方式调用自己的属性)。
import a.b.c.d.e.f from a.b.c.d.e.f import xxx # 以上两种导入方式中, .f左侧的a b c d e都必须是包
例如:
2、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间
3、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
2. 相对导入
# 相对导入 # .:代表当前文件夹 # ..:代表上一层文件夹 from .m1 import f1 from .cc.m3 import f3
# from bb.m1 import f1 from ..m1 import f1 def f3(): print('这是m3') f1()
相对导入有非常大的局限性, 仅限于包内模块之间相互引用, 不能跨出包.
绝对导入是没有任何限制的, 绝对导入是一种通用的导入方式.
包内模块之间的导入推荐使用相对导入, 因为如果采用绝对导入的方法, 当后面需要改包的时候, 相应的导入也得改.
不管是绝对导入, 还是相对导入, 都是包的设计者所做的事, 使用者不用考虑.
from bb import * *表示从bb中导入__init__中的所有名字.
总结: 自己很少会涉及到自定义包, 如果要写大项目, 可能会自定义包.