今日主要内容
- 包
一、包
(一)什么是包
- 只要是含有
__init__.py
文件的文件夹就是一个包 - 包的本质其实就是一个文件夹,利用包将不同功能的模块组织起来,以此来提高程序的结构性和可维护性
- 包是用来导入的,不是用来执行的,所以它和软件开发规范分文件管理还是有区别的,一个是项目,一个是用来导入的包
- 正因为包是用来导入的,所以运行文件一定要放在包的外面
(二)创建一个包
-
利用代码创建一个包
import os os.makedirs('glance/api') os.makedirs('glance/cmd') os.makedirs('glance/db') l = [] l.append(open('glance/__init__.py','w')) l.append(open('glance/test.py','w')) l.append(open('glance/api/__init__.py','w')) l.append(open('glance/api/policy.py','w')) l.append(open('glance/api/versions.py','w')) l.append(open('glance/cmd/__init__.py','w')) l.append(open('glance/cmd/manage.py','w')) l.append(open('glance/db/models.py','w')) map(lambda f:f.close() ,l)
- 下述所有内容,均以此图结构为基础
(三)__init__.py
文件
-
在我们导入包的时候,其实本质上导入的就是
__init__.py
文件,解释器会自动执行__init__.py
文件中的内容# glance/__init__.py print("这里是glance下的__init__.py文件") # run.py import glance 运行结果: 这里是glance下的__init__.py文件
(四)包的导入
- 包的导入,须注意两点内容:
- 导入时无论是使用
import
还是使用from xxx import xxx
导入,点的前面必须是一个包 - 使用
from xxx import xxx
导入时,import前可以出现点,import后不能出现点
- 导入时无论是使用
-
常规导入
- import导入
# policy.py def policy_func(): print("这是policy文件中的函数") # run.py import glance.api.policy glance.api.policy.policy_func() 运行结果: 这是policy文件中的函数 # 成功导入
- from import导入
# policy.py def policy_func(): print("这是policy文件中的函数") # run.py from glance.api.policy import policy_func policy_func() 运行结果: 这是policy文件中的函数 # 成功导入
-
包内部之间的导入:
-
包内部之间的相互引用,只能用绝对导入和相对导入,不能直接导入,比如
policy.py
文件需要导入versions.py
文件中的函数,如果直接import导入会报找不到该模块的错误- 包内部互相引用的时候不能直接导入
# versions.py def versions_func(): print("这是versions文件中的函数") # policy.py import versions # 直接导入versions模块,在外面的run文件中运行,就无法找到versions模块 def policy_func(): versions.versions_func() print("这是policy文件中的函数") # run.py from glance.api import policy policy.policy_func() 运行结果: ModuleNotFoundError: No module named 'versions'
- 原因分析:如果直接在policy文件中运行程序,完全没有问题,因为此时policy文件的模块查找路径中包含versions模块,但是**包是用来导入的,如果在包外的run文件中导入policy模块,此时模块查找路径就变为了run文件所在的路径,所以当policy文件导入versions模块时,路径下并没有versions模块,所以找不到该模块
绝对导入:
# versions.py def versions_func(): print("这是versions文件中的函数") # policy.py from glance.api import versions def policy_func(): versions.versions_func() print("这是policy文件中的函数") # run.py from glance.api import policy policy.policy_func() 运行结果: 这是versions文件中的函数 这是policy文件中的函数
- 相对导入:
# versions.py def versions_func(): print("这是versions文件中的函数") # policy.py from . import versions def policy_func(): versions.versions_func() print("这是policy文件中的函数") # run.py from glance.api import policy policy.policy_func() 运行结果: 这是versions文件中的函数 这是policy文件中的函数
- 只要使用了相对导入的模块,只能作为模块使用,不能作为脚本(终端中直接运行的文件成为脚本)使用,说白了就是不能直接运行
# versions.py def versions_func(): print("这是versions文件中的函数") # policy.py from . import versions def policy_func(): versions.versions_func() print("这是policy文件中的函数") 运行结果: ImportError: cannot import name 'versions'
-
-
单独导入包,并使用包内的包或模块
- 单独导入一个包,其本质上导入的只是
__init__.py
文件,包中其他的文件并没有被导入
# policy.py def policy_func(): print("这是policy文件中的函数") # run.py import glance # 只导入了__init__.py文件 glance.api.policy.policy_func() # 并不能使用 运行结果: AttributeError: module 'glance' has no attribute 'policy'
- 此时就要利用到
__init__.py
文件了,__init__.py
文件在包中起到了交接管理的作用,可以在__init__.py
文件中导入每个子文件,也可以控制其是否能被导入,所以每一个包中必须要有__init__.py
文件
# policy.py def policy_func(): print("这是policy文件中的函数") # glance/__init__.py from . import api # glance/api/__init__.py from . import policy # run.py import glance glance.api.policy.policy_func() 运行结果: 这是policy文件中的函数
- 直接调用模块中的方法
# policy.py def policy_func(): print("这是policy文件中的函数") # glance/__init__.py from .api import * # glance/api/__init__.py from .policy import * # run.py import glance glance.policy_func() 运行结果: 这是policy文件中的函数
-
还可以通过
__all__
来控制模块和模块中函数的导入- 控制模块导入
# glance/__init__.py from .api import * # glance/api/__init__.py __all__ = ["versions"] # 只能导入versions,其余api下模块都不能被导入 # run.py import glance glance.policy 运行结果: AttributeError: module 'glance' has no attribute 'policy'
- 控制方法导入
# policy.py def policy_func(): print("这是policy文件中的func") def policy_foo(): print("这是policy文件中的foo") # glance/__init__.py from .api import * # glance/api/__init__.py from .policy import * __all__ = ["policy_foo"] # 控制只能导入foo函数,其余函数都不能被导入 # run.py import glance glance.policy_func() 运行结果: AttributeError: module 'glance' has no attribute 'policy_func'
- 单独导入一个包,其本质上导入的只是