共计 1984 个字符,预计需要花费 5 分钟才能阅读完成。
摘要:具体解说了相对路径和绝对路径的援用办法。
在某次运行过程中呈现了如下两个报错:
报错 1:ModuleNotFoundError: No module named '__main__.src_test1'; '__main__' is not a package
报错 2:ImportError: attempted relative import with no known parent package
于是基于这两个报错探索了一下 python3 中的模块互相援用的问题,上面来一一解析,请急躁看完。
好的,咱们先来结构第一个错:
测试代码构造如下:
|--- test_main.py
|--- src
|--- __init__.py
|--- src_test1.py
|--- src_test2.py
src_test2.py 代码
class Test2(object):
def foo(self):
print('I am foo')
src_test1.py 代码,援用 Test2 模块
from .src_test2 import Test2
def fun1():
t2 = Test2()
t2.foo()
if __name__ == "__main__":
fun1()
此时运行 src_test1.py 报错“No module named ‘__main__.src_test1’; ‘__main__’ is not a package”
问题起因:
次要在于援用 src_test2 模块的时候,用的是相对路径 ”.”,在 import 语法中翻译成 ”./”,也就是当前目录下,按这样了解也没有问题,那为什么报错呢?
从 PEP 328 中,咱们找到了对于 the relative imports(绝对援用)的介绍
艰深一点意思就是,你程序入口运行的那个模块,就默认为 主模块 ,他的 name 就是‘main’,而后会将本模块 import 中的点(.) 替换成‘__main__’,那么 .src_test2 就变成了 __main__.src_test2,所以当然找不到这个模块了。
解决办法:
因而,倡议的做法是在 src 同层级目录创立 援用模块 test_main.py(为什么不在 src 目录下创立,待会下一个报错再讲),并援用 src_test1 模块,代码如下:
from src.src_test1 import fun1
if __name__ == "__main__":
fun1()
test_src 代码:
from src_test1 import fun1
if __name__ == "__main__":
fun1()
执行报错:ImportError: attempted relative import with no known parent package
问题起因:
当执行 test_src 时,按上文了解,此时执行文件所在的目录为根目录,那么援用 test1 的时候,须要留神的是,此时 test1 的 name 属性不再是 src.src_test1,因为程序感知不到 src 的存在,此时他的绝对路径是 src_test1,此时再次援用相对路径查找的 test2,同样的步骤,须要先找到父节点,而此时他本人就是根节点了,曾经没有父节点了,因而报错“no known parent package”。
解决办法:
此时为了防止父节点产生矛盾,因而将 test1 中的引入去掉绝对援用即可
from .src_test2 import Test2 --> from src_test2 import Test2
持续深刻:
那应用相对路径和绝对路径,编译器是怎么找到这个模块的呢?
执行 import 的时候,存在一个引入的程序,即优先查找执行目录下有没有此文件,如没有,再查找 lib 库下,如还没有,再查找 sys.path 中的门路,如再没有,报错。
所以不论是当前目录,还是 sys.path 中的目录,都能够查到 src_test2 这个模块,就能够编译胜利。
号外:
解决完上述问题后,不论咱们用哪种形式,咱们调试代码时,都是单个文件调试,但此时根目录就不对了,import 形式又要改变,执行起来很麻烦,所以这里举荐另一种形式(有更好的形式欢送留言),应用 sys.path.append()的办法
import sys,os
sys.path.append(os.getcwd())
from src.src_test2 import Test2
应用 append 的形式,将程序文件根目录放进了 sys.path 中,而后再援用 相对 门路,这样的形式,不论应用上文中的第一或第二执行形式都能够调用,也能够独自编译 test1 文件,不必批改 import 门路,也是绝对平安的形式。然而毛病就是,如果你批改了某一个包名,须要将所有援用中央都批改一下,工作量大,所以就地取材。
综上,具体解说了相对路径和绝对路径的援用办法,当初你应该对 import 导入的问题有了清晰的了解吧
备注:本文基于 Python3.7 版本测试
点击关注,第一工夫理解华为云陈腐技术~