当前位置: 首页 > 后端技术 > Python

终于明白Python模块之间相互引用的问题

时间:2023-03-25 21:42:45 Python

摘要:详细讲解相对路径和绝对路径的引用方式。在某次操作中,出现如下两个错误:错误一:ModuleNotFoundError:Nomodulenamed'__main__.src_test1';'__main__'isnotapackageError2:ImportError:attemptedrelativeimportwithnoknownparentpackage于是基于这两个报错探讨了python3中模块间相互引用的问题。让我们一一分析。请耐心阅读。好,我们先构造第一个错误:测试代码结构如下:|---test_main.py|---src|---__init__.py|---src_test1.py|---src_test2.pysrc_test2.py代码classTest2(object):deffoo(self):print('Iamfoo')src_test1.py代码,引用Test2模块from.src_test2importTest2deffun1():t2=Test2()t2.foo()if__name__=="__main__":fun1()此时运行src_test1.py报错"Nomodulenamed'__main__.src_test1';'__main__'isnotapackage"问题原因:主要原因就是在引用src_test2模块时,相对路径“.”在导入语法中被翻译成“./”,即在当前目录下。这样理解是没有问题的,那为什么会报错呢?从PEP328中,我们找到了相对导入(relativereferences)的介绍。通俗的意思就是你的程序入口运行的模块默认是主模块,它的名字叫'main',然后这个模块将import中的点(.)替换为'__main__',然后.src_test2变成了__main__.src_test2,当然找不到这个模块了。解决方法:因此,推荐的做法是在src同级目录下创建一个引用模块test_main.py(为什么不在src目录下创建呢,下次报错的时候再说),以及引用src_test1模块,代码如下:fromsrc.src_test1importfun1if__name__=="__main__":fun1()test_src代码:fromsrc_test1importfun1if__name__=="__main__":fun1()Executionerror:ImportError:attemptedrelativeimportwithnoknownparentpackage原因:执行test_src时,按上面理解,执行文件所在的目录是根目录。在引用test1时,需要注意的是此时test1的name属性不再是src.src_test1,因为程序无法感知src的存在。这时它的绝对路径就是src_test1。这时,它又使用相对路径找到了test2。同样的步骤,需要先找到父节点。此时本身就是根节点,没有父节点,所以报错“noknownparentpackage”。解决方法:此时为了避免父节点冲突,将test1中import中的相对引用去掉。from.src_test2importTest2-->fromsrc_test2importTest2继续深入:编译器如何使用相对路径和绝对路径?你在哪里找到这个模块?执行import时,有一个导入顺序,即先查找执行目录下的文件,如果没有,再查找lib库,如果没有,再查找sys.path中的路径,如果没有,报一个错误。这样无论是当前目录还是sys.path中的目录,都能找到src_test2模块,编译成功。Extra:解决了以上问题后,无论我们使用哪种方法,在调试代码的时候,都会用单个文件来调试代码,但是此时根目录不对,需要重新更改导入方式,执行起来很麻烦,所以这里推荐另外一种方法(如果有更好的方法,欢迎留言),使用sys.path.append()方法importsys,ossys.path.append(os.getcwd())fromsrc.src_test2importTest2使用append方法,将程序文件的根目录放到sys.path中,然后引用绝对路径。这样无论是上面的第一种还是第二种执行方式都可以调用,而且test1文件也可以在不修改导入路径的情况下单独编译。这也是一种相对安全的方式。但缺点是如果修改某个包名,需要修改所有引用,工作量大,所以要因地制宜。综上所述,相对路径和绝对路径的引用方式已经详细说明了。现在你应该对导入问题有了清晰的认识。备注:本文基于Python3.7版本测试。