包
一、包介绍
随着模块数目的增多,把所有模块不加区分地放到一起也是极不合理的,于是Python为我们提供了一种把模块组织到一起的方法,即创建一个包。包就是一个含有__init__.py文件的文件夹,文件夹内可以组织子模块或子包,例如
pool/ #顶级包
├── __init__.py
├── futures #子包
│ ├── __init__.py
│ ├── process.py
│ └── thread.py
└── versions.py #子模块
需要强调的是
#1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
#2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块
二、绝对导入与相对导入
针对包内的模块之间互相导入,导入的方式有两种
2.1 绝对导入
只要能够从环境变量中找见的就是绝对导入
# 始终以执行文件所在的环境变量sys.path为基准
from aaa.bbb.ccc.m1 import f1 # 可以精确到变量名
from aaa.bbb.ccc import m1 # 也可以精确到模块名
多个模块导入
#m1被导入文件的内容:
import m2
def f1():
print('from f1')
m2.f2()
#m2被导入文件的内容:
def f2():
print('from f2')
#run运行文件的内容:
import m1
m1.f1()
# 运行文件直接使用被导入文件m2的名字
m1.m2.f2()
文件夹下的模块
aaa文件中的m1.py,m2.py
执行以上代码会报错:ModuleNotFoundError: No module named 'm1'
只改执行文件的内容:from aaaimport m1也会报错:ModuleNotFoundError: No module named 'm2'(因为找m2是基于执行文件所在的路径来找的,现在在该路径下寻找不到m2)
#m1被导入文件的内容:
from aaa import m2 # 方法二(原因:aaa在环境变量中)
def f1():
print('from f1')
m2.f2()
#m2被导入文件的内容:
def f2():
print('from f2')
#run运行文件的内容:
# import sys # 方法一,把aaa加入到环境变量中
# sys.path.append('aaa的路径')
import m1
m1.f1()
2.2 相对导入
"""
句点符(.)
.代表的是当前路径
..代表上一层路径
..\..在路径中表示上上一层目录
"""
相对导入打破了以执行文件所在的路径为基准的原则, 只考虑两个文件之间的位置,以模块自身路径为准
aaa中bbb文件的m1.py,m2.py
#m1被导入文件的内容:
from . import m2
def f1():
print('from f1')
m2.f2()
#m2被导入文件的内容:
def f2():
print('from f2')
#run运行文件的内容:
import aaa.bbb.m1
m1.f1()
aaa下的bbb下有m1,ccc.ccc下有m2
from .ccc import m2
当文件中出现了相对导入的句式,该文件就不能当成执行文件运行了,只能被当成导入文件使用
三、包的使用
3.1 导入包与__init__.py
包是一些列模块的集合体,本质上就是文件夹,它与普通文件夹有着微小的区别
包里面有一个__init__.py文件(只放初始化逻辑)
包属于模块的一种,因而包以及包内的模块均是用来被导入使用的,而绝非被直接执行,首次导入包(如import pool)同样会做三件事:
-
运行执行文件,产生执行文件的名称空间
-
运行__init__.py文件, 把该文件中产生的名字保存在名称空间中
-
在执行文件中,产生一个包名字bbb指向包的名称空间
4.在当前执行文件所在的名称空间中得到一个名字bbb,该名字指向__init__.py的名称空间,例如bbb.xxx和bbb.yyy中的xxx和yyy都是来自于bbb下的__init__.py,也就是说导入包时并不会导入包下所有的子模块与子包
强调
1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如import 顶级包.子包.子模块,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
2、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间
3、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
3.2 导入包中的模块
如果只想用包中某几个模块 那么还是按照之前的导入方式即可(指名道姓的导入)
from bbb import md1, md2
3.3 直接导入包名
导入包名其实就是导包下面的__init__.py文件,该文件内有什么名字就可以通过包名点什么名字
#方式一
#可以在__init__.py文件中写入:
from bbb import md1, md2
#这样就可以在运行文件中使用md包下面文件(md1, md2)里面的名字:
print(bbb.md1.name)
print(bbb.md2.name)
#方式二
# 也可以在__init__.py文件中写入:
from bbb.md1 import f1
from bbb.md2 import f2
#就可以直接在运行文件中使用名字:
import bbb
bbb.f1()
bbb.f2()