模块循环导入问题
在一个文件夹内建立三个.py文件,m1.py 和 m2.py 和 run.py,前两者作为被导入模块,run.py为执行文件
#执行文件内容 import m1 #m1模块内容 print('正在导入m1...') from m2 import y x = 1 #m2模块内容 print('正在导入m2...') from m1 import x y = 2 #运行run,结果: 正在导入m1... 正在导入m2... ImportError: cannot import name 'y'
过程分析:
1首先要明确的是:谁是执行文件,谁是被导入模块
2.首次导入模块发生的三件事
执行run.py时,申请了run.py的名称空间,首次导入m1时,申请m1这个被导入模块的名称空间,开始执行m1模块内的代码,执行到from m2 import y时开始申请m2的名称空间,执行m2的模块体代码,再执行到from m1 import x 时,此时内存中已经存在m1的名称空间(虽然m1才执行到from m2 import y这里),python就直接去m1模块的名称空间中去寻找x,并试图在自己的名称空间内用一个变量名x指向m1中x的内存地址,但是此时的m1中还未存在x与1这个值的绑定关系
解决方法:
1.导入模块语句放在名字定义之后
#执行文件内容 import m1 print(m1.y) #m1模块内容 print('正在导入m1...') x = 1 from m2 import y #m2模块内容 print('正在导入m2...') y = 2 from m1 import x #运行run,结果: 正在导入m1... 正在导入m2... 2
2:导入模块就是为了使用的,如果是在函数内使用被导入模块,完全可以将导入语句放在函数内
#执行文件内容 import m1 m1.f1() #m1模块内容 print('正在导入m1...') def f1(): from m2 import y,f2 print('m1.f1--->y',y) f2() x=1 #m2模块内容 print('正在导入m2...') def f2(): from m1 import x print('m2.f2--->x',x) y = 'm2' #运行run,结果: 正在导入m1... 正在导入m2... m1.f1--->y m2 m2.f2--->x m1
这是利用了,函数在定义阶段只检测语法,而不执行代码的原理
模块的搜索路径原则:内存中已经加载过的---->内置----->sys.path(注意:sys.path的第一个路径为执行文件的所在当前文件夹)
值得注意的是:所有被导入模块的搜素路径都是以执行文件的sys.path为准
例如我们在建立dir0文件夹,在其内建立dir文件夹以及与其同一级的run.py执行文件,在dir文件夹下建立两个同一级别的m1.py,m2.py
#这些文件run.py的内容 from dir import m3 #m1模块的内容 def f1(): print('m1.f1') #m2模块的内容 import m1 m1.f1() #运行结果 ModuleNotFoundError: No module named 'm1' 当我们将import m1 改为from dir import m1就正确了
模块的绝对导入和相对导入:
绝对导入:以执行文件的sys.path为起点导入
优点:执行文件和被导入模块都可以使用 缺点:导入麻烦
相对导入:参照当前所在文件的文件夹为起点查找
用法:一个点代表当前文件夹,点点代表上一级,点点点代表上一级的上一级
所以:上个模块搜索路径的例子, m3模块中的代码可以改写为:
from .m1 import f1 f1()