代码急转弯——from . import
1、import = 我扫你
导入,用于实现在a文件中调用b文件的函数,即我如何调你?
格式1:
from m1 import fun
在m1.py文件中定义了函数fun,如果想在a.py文件中调用fun,先编写上述命令导入指定的fun函数,然后就能在a.py中调用fun函数了。
格式2:
from m1 import *
导入了m1.py中的各个函数,自然也包括fun函数。
格式3:
import m1
没有指定从m1中导入的对象,在调用fun时需要写上前缀,m1.fun()。
前面假设m1是一个脚本文件m1.py,实际上,m1还可以是一个子目录。这时,用同样的命令,可导入在 ./m1/__init__.py 中定义的fun函数。
2、问题引入 = 你扫谁
import解决了我调你的问题,它又带来一个你调谁的问题。
a.py为了执行m1中的函数,需要执行导入操作。如果m1还要执行m2中的函数,当然也需要在m1中导入m2。现在出了一个问题,在如下目录结构中,dir1中有两个文件a.py和m2.py,dir2中也有两个文件m1.py和m2.py.现在有两个m2.py,它们分别为位于调用者目录和模块所在目录中。问m1中的 import m2 语句导入的是哪一个m2.py?实际上,这个问题就是谁是当前目录?
E:\dir1
| m2.py
| a.py
\—dir2
m1.py
m2.py
答案是m1将导入dir1中的m2。下面通过实验进行求证(test.py)。
首先构建实验环境,主要是创建目录和文件,代码如下,
# -*- coding: utf-8 -*-
# test.py
import os
if not os.path.exists('dir2'):
os.mkdir('dir2')
def to_file(fname, cont_str):
with open(fname, 'w') as f:
f.write(cont_str)
s1 = '''import m2
m2.f()'''
to_file('dir2/m1.py', s1)
s2 = '''def f():
print('in m2.f()')'''
to_file('m2.py', s2)
s3 = '''def f():
print('in dir2/m2.f()')'''
to_file('dir2/m2.py', s3)
# In[2]
from importlib import reload
import dir2.m1 as m1
reload(m1)
假设当前位于dir1子目录中。
1)创建子目录dir1/dir2;
2)创建文件dir1/dir2/m1.py,s1为文件内容;
3)创建文件dir1/m2.py,s2为文件内容;
4)创建文件dir1/dir2/m3.py,s3为文件内容;
注意,m1.py、m2.py、m3.py的位置。
在单元# In[2]中,执行了导入m1的操作。为了使得每次执行都能打印执行效果,调用了reload。
运行结果
in m2.f()
in m2.f()
第一次执行,有两行结果,再次执行,只有一行结果。结果表明,m1中的语句import m2导入的是调用者目录中的dir1/m2.py文件,而不是dir1/dir2/m2.py。
【问题】来了,如果m1.py想要执行的是dir2中的dir1/dir2/m2.py,怎么办?这个选择应该是更符合直觉,因为编写m1.py时,也编写了和它在一起的那个dir1/dir2/m2.py更为合理。
3、from . import xxx = 你想扫谁就扫谁
终于可以说明 from . 的作用了。为了避免冲突,把dir1/dir2/m2.py改名为dir1/dir2/m3.py。
import m2
from . import m3
from .m3 import f
前两条条命令分别导入dir1和 dir2中的m2.py和m3.py,第三条命令是一个语法糖衣,使得导入指定函数的格式得以成立。再做一次实验,代码如下:
# -*- coding: utf-8 -*-
'''
E:\dir1
│ m2.py
│ test.py
└─dir2
m1.py
m3.py
'''
import os
if not os.path.exists('dir2'):
os.mkdir('dir2')
def to_file(fname, cont_str):
with open(fname, 'w') as f:
f.write(cont_str)
s1 = '''import m2
from . import m3
from .m3 import f
m2.f()
m3.f()
f()
'''
to_file('dir2/m1.py', s1)
s2 = '''def f():
print('in m2.f()')'''
to_file('m2.py', s2)
s3 = '''def f():
print('in dir2/m3.f()')'''
to_file('dir2/m3.py', s3)
# In[2]
from importlib import reload
import dir2.m1 as m1
reload(m1)
运行结果
in m2.f()
in dir2/m3.f()
in dir2/m3.f()
结论,from . import xxx 使得被导入的模块有机会导入,自身所在目录中自己的模块,既你说是谁就是谁。