python之模块详情
循环导入
在初学模块时,我们有些时候会出现两个文件彼此导入,这时候可能会有报错。
比如有以下两个py文件
a.py
import b
name = '来自a.py'
print(b.name)
b.py
import a
name = '来自b.py'
print(a.name)
此时无论是执行a.py或是b.py都会报错,这是因为某个名字还没有被创建就被使用了。
解决办法
- 将导入模块的句式写在定义名字的下面
# 修改b.py文件为
name = '来自b.py'
import a # 放在定义名字的下面
print(a.name)
"""此时运行a.py文件就不会报错了,想要运行b.py文件就要修改a.py里的代码"""
- 将导入模块的句式写在函数体代码内
# 修改b.py文件为
# 修改b.py文件为
def index():
import a
print(a.name)
name = '来自b.py'
"""此时a.py中想要使用b.py里的名称就不会报错了"""
所以在编程过程中,循环导入问题我们一定要尽量去避免出现。
py文件类型
python文件可以被分为两种类型
- 执行文件
- 被导入文件
我们可以让py文件输出内置变量__name__来查看此时的文件是执行文件还是被导入文件。
创建a.py文件
print(__name__)
创建b.py文件
import a
执行a.py,执行结果:
__main__
执行b.py,执行结果:
a
可以看出,如果是执行文件时,输出__name__变量的值为__main__,而如果是被导入文件时,输出__name__变量的值为被导入文件的名称。
所以我们一般会利用这一结果用于区分被导入的代码和测试代码
if __name__ == '__main__':
代码块
"""
如果此文件是执行文件的时候才会执行if里面的代码
被别的文件导入的时候不会执行if里面的代码
"""
模块的查找顺序
模块查找顺序:内存空间-->内置模块-->sys.path中(类似于环境变量)。
在导入一个模块时,如果该模块已加载到内存空间中,就可以直接引用;在内存空间找不到该模块时,就会去内置模块中寻找,还是找不到的话就会去sys.path中查找,都找不到时就会报错。
sys.path的内容
# 导入模块sys
import sys
print(sys.path) # 输出sys.path
sys.path里的内容是一个列表,列表里面存放了很多路径。当内存中和内置中都没有要查找的模块时,就会去sys.path里的路径中挨个查找。
案例
创建如下文件和文件夹
a.py
import b
name = '来自a.py'
print(b.name)
b.py
name = '来自b.py'
main.py
import a
print(a.name)
此时运行main.py会报错说找不到a,因为导模块时没有在内存、内置和sys.path中找到a。
解决办法一:使用sys.path.append添加路径
修改main.py
import sys
sys.path.append(r'.\aaa') # 添加文件夹aaa的路径即可
import a
print(a.name)
解决办法二:使用from...import...句式查找
修改main.py
from aaa import a
print(a.name)
但是此时运行main.py文件还是会报错,说模块b找不到啦,这是因为a.py执行代码导入模块b,查找模块b是按照main.py的sys.path路径查找的,所以会找不到b,所以还要修改a.py文件代码
修改a.py
from aaa import b
name = '来自a.py'
print(b.name)
这时候就没有问题啦!
相对导入与绝对导入
在导入模块的时候一切查找模块的句式都是以执行文件的路径为准,无论导入的句式是在执行文件中还是在被导入文件中。
绝对导入
永远按照执行文件所在的路径一层层往下查找。
如下图:
如果main.py想要导入a.py,并使用绝对导入
# main.py代码
from aaa.bbb.ccc import a
相对导入
相当导入打破了必须参照执行文件的所在路径的要求,只需要考虑当前模块所在的路径然后使用特殊符号"."去查找其他模块即可。
.表示当前路径
..表示上一层路径
../..表示上上一层路径
如下图:
如果我想让在ccc文件夹中的c.py中想要导入b.py
# c.py代码
from .. import b
注意:相对导入只能在被导入文件中使用,不能在执行文件中使用。
包
从专业角度讲:包就是内部含有__init__.py的文件夹。
从实际角度讲:包就是多个模块的结合体(内部存放了多个模块文件)。
在导入普通文件夹里面的模块时,需要用绝对导入或者是给sys.path添加路径,但是导入包里面的模块时,是不需要这么做的,设计好__init__.py文件后,只要用import + 包名就可以了。
创建如下目录结构
a.py
name = '来自a.py'
b.py
name = '来自b.py'
__init__.py
from . import a
from . import b
name_from_a = a.name
name_from_b = b.name
main.py
import pack
print(pack.name_from_a)
print(pack.name_from_b)
执行main.py结果
来自a.py
来自b.py
以上是包的使用方法,当然了,你也可以把包当成普通文件夹使用。