一、包介绍

随着模块数目的增多,把所有模块不加区分地放到一起也是极不合理的,于是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)同样会做三件事:

  1. 运行执行文件,产生执行文件的名称空间

  2. 运行__init__.py文件, 把该文件中产生的名字保存在名称空间中

  3. 在执行文件中,产生一个包名字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()
posted @ 2023-03-12 20:19  星空看海  阅读(40)  评论(0编辑  收藏  举报