• 售前

  • 售后

热门帖子
入门百科

浅析Python模块之间的相互引用标题

[复制链接]
王建新1 显示全部楼层 发表于 2021-10-25 20:27:54 |阅读模式 打印 上一主题 下一主题
摘要:详细讲授了相对路径和绝对路径的引用方法。
在某次运行过程中出现了如下两个报错:
  1. 报错1: ModuleNotFoundError: No module named '__main__.src_test1'; '__main__' is not a package
  2. 报错2: ImportError: attempted relative import with no known parent package
复制代码
于是基于这两个报错探究了一下python3中的模块相互引用的问题,下面来逐个解析,请耐心看完。
好的,我们先来构造第一个错,测试代码布局如下:
  1. |--- test_main.py
  2. |--- src
  3. |--- __init__.py                              
  4.   |--- src_test1.py
  5.   |--- src_test2.py
复制代码
src_test2.py 代码
  1. class Test2(object):
  2.   def foo(self):
  3.     print('I am foo')
复制代码
src_test1.py 代码,引用Test2模块
  1. from .src_test2 import Test2
  2. def fun1():
  3.   t2 = Test2()
  4.   t2.foo()
  5. if __name__ == "__main__":
  6.   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模块,代码如下:
  1. from src.src_test1 import fun1
  2. if __name__ == "__main__":
  3.   fun1()
复制代码
那为什么这样实行就可以了呢,其中原理是什么呢?我是这样明白的(欢迎纠正):test_main实行时,他被当做根目次,因此他引用的src.src_test1 是绝对路径,这样引用到哪都不会错,此时他的name=‘main',当实行src_test1的时间,注意了此时test1的name是 src.src_test1,那么在test1中利用的是相对路径,查找逻辑是先找到父节点(src目次),再找父节点下面的src_test2,因此可以乐成找到,Bingo!
辅证:

构造一个例子,就可以明白上面的 实行目次就是根目次 的说法了,修改test1,使引用test_main:
  1. from .. import test_main
  2. 报错:ValueError: attempted relative import beyond top-level package
复制代码
OK,那继承构造第二个报错:
上文中说过,办理main 的问题,就是创建一个模块,来调用利用相对路径的模块,那么为什么我不能在雷同目次下创建这个文件来调用呢?让我们来测试下代码:
创建test_src.py文件,代码布局变更如下:
  1. |--- test_main.py
  2. |--- src
  3. |--- __init__.py                              
  4.   |--- src_test1.py
  5.   |--- src_test2.pys  |--- test_src.py
复制代码
test_src 代码:
  1. from src_test1 import fun1
  2. if __name__ == "__main__":
  3.   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中的引入去掉相对引用即可
  1. from .src_test2 import Test2  -->  from src_test2 import Test2
复制代码
继承深入:

那利用相对路径和绝对路径,编译器是怎么找到这个模块的呢?
实行import的时间,存在一个引入的次序,即优先查找实行目次下有没有此文件,如没有,再查找lib库下,如还没有,再查找sys.path中的路径,如再没有,报错。
所以不管是当前目次,还是 sys.path中的目次,都可以查到 src_test2这个模块,就可以编译乐成。
号外:

办理完上述问题后,不管我们用哪种方式,我们调试代码时,都是单个文件调试,但此时根目次就不对了,import方式又要改动,实行起来很麻烦,所以这里保举另一种方式(有更好的方式欢迎留言),利用sys.path.append()的方法
  1. import sys,os
  2. sys.path.append(os.getcwd())
  3. from src.src_test2 import Test2
复制代码
利用append的方式,将步调文件根目次放进了sys.path中,然后再引用绝对路径,这样的方式,不管利用上文中的第一或第二实行方式都可以调用,也可以单独编译test1文件,不消修改import路径,也是相对安全的方式。但是缺点就是,如果你修改了某一个包名,需要将全部引用地方都修改一下,工作量大,所以因地制宜。
综上,详细讲授了相对路径和绝对路径的引用方法,现在你应该对import导入的问题有了清晰的明白吧
备注:本文基于Python3.7版本测试
到此这篇关于Python模块之间的相互引用问题的文章就先容到这了,更多相干Python模块引用内容请搜索脚本之家从前的文章或继承浏览下面的相干文章希望大家以后多多支持脚本之家!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作