摘要:详细讲解了相对路径和绝对路径的引用方法。
在某次运行过程中出现了如下两个报错:
报错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目来&源gao@dai!ma.com搞$代^码%网录下创建,待会下一个报错再讲),并引用src_test1模块,代码如下:
from src.src_test1 import fun1 if __name__ == "__main__": fun1()
那为什么这样执行就可以了呢,其中原理是什么呢?我是这样理解的(欢迎纠正):test_main执行时,他被当做根目录,因此他引用的src.src_test1 是绝对路径,这样引用到哪都不会错,此时他的name=‘main’,当执行src_test1的时候,注意了此时test1的name是 src.src_test1,那么在test1中使用的是相对路径,查找逻辑是先找到父节点(src目录),再找父节点下面的src_test2,因此可以成功找到,Bingo!
辅证:
构造一个例子,就可以理解上面的 执行目录就是根目录 的说法了,修改test1,使引用test_main:
from .. import test_main 报错:ValueError: attempted relative import beyond top-level package
OK,那继续构造第二个报错:
上文中说过,解决main 的问题,就是创建一个模块,来调用使用相对路径的模块,那么为什么我不能在相同目录下创建这个文件来调用呢?让我们来测试下代码:
创建test_src.py文件,代码结构变更如下:
|--- test_main.py |--- src |--- __init__.py |--- src_test1.py |--- src_test2.pys |--- test_src.py
test_src 代码:
from src_test1 import fun1 if __name__ == "__main__": fun1()