【笔记】Python报错ImportError: attempted relative import with no known parent package

报错关键词
        相对导入(relative import):报错模块(模块,区别于脚本不直接作为主程序运行,是一系列对象定义的集合)存在使用相对导入的包内模块调用关系,也即其中存在以 .(平级目录)或..(父级目录)起头的import语句。例如,from .<subpackage|module> import <subpackage|module|func> 表示从报错模块平级目录的包或模块中调用嵌套的包或模块或函数。
        包(package):利用文件夹组织的模块的集合,一般通过在各层级文件夹中放置__init__.py指示当前文件夹为一个包。
        无法识别的包文件(no known parent package):当前 Python 解释器运行路径(python path/to/main.py 中 python 命令的执行位置)无法查找到当前执行脚本引用的包含相对导入的模块的最小包结构。


常见问题汇总及排查
1. 在脚本中使用相对导入
问题:相对导入是存在于包结构中,并在模块中使用的概念,而由 Python 解释器执行的程序是脚本文件,不应该存在相对导入。
解决方案:请使用绝对导入导入同级模块或包。若本地包文件存在于其它目录层级,考虑重新安排目录结构,或使用 PYTHONPATH 环境变量将本地包路径手动添加到 Python 解释器可识别包路径。详见文末扩展内容。

详细解决方案
1. 【看这段基本够了】使用相对导入的时机
💡 你真的需要相对导入吗?如果你明确地知晓答案,也许就不应该出现这个问题。

相对导入应当使用在包(由多个或多目录层级 *.py 模块组成)内模块中的 import 语句,用于内部模块功能之间的相互调用,而包内模块及功能则应当通过包外脚本调用。

因此你应该这样思考和解决:当前的代码结构真的存在包-模块层级关系吗?如果存在,你应当在包外部通过脚本引用任意包-模块功能;如果不存在,你应当使用绝对导入直接导入同级目录模块。

2. 【扩展】如果你真的需要在包平级目录以外的位置调用包
当你意识到自己当前所处的位置确实为包外部,但尝试通过包平级目录以外的目录导入该包时,也可能遭遇导入问题。

Python的默认包搜索路径为sys.path,一般指向当前Python环境pip默认安装包的目录。

你可以通过export PYTHONPATH=$PWD快速添加当前目录(包所在目录)到搜索路径。如为开发中包项目,建议使用   direnv 进行环境管理,如为长期依赖某些本地未发布的代码(包、模块)脚本文件,建议通过代码添加本地代码所在目录到 sys.path

参考链接
Stack Overflow: Relative imports for the billionth time
python3-cookbook: 10.9 将文件夹加入到sys.path

* 扩展:名词解释
脚本(script)
通过执行该文件能够完成某项任务,其中存在必要的任务执行逻辑(一般通过 if __name__ == '__main__:' 代码块明确任务的整体执行逻辑),notebook 也可以列入这一范畴;

模块(module)
Python 对象的集合,其内容为功能实现,目的是方便其它模块和脚本调用,因此不存在自身的运行逻辑(也即需要通过在其它文件中使用 import 语句调用,而非直接通过 python module.py 运行);

包(package)
如果一个目录中存在多个模块,可以通过创建 __init__.py 文件将该当前目录标识为一个包。若多个模块放置于具有多层嵌套的目录当中,其逻辑关系为包(根目录)-> 子包(子目录)-> 模块(*.py);

绝对导入(absolute import)
从包/模块外部,按照目标模块的存在路径从外到内进行导入。绝对导入可以检索到三种来源的包:

Python自带或pip安装的包;
Python解释器启动位置同层模块和包;
人为添加到系统环境变量 PYTHONPATH 的模块和包。
绝对导入示例:

单独的模块:import module;
模块位于包内部(不存在子包):from package import module;
模块位于包内部(存在子包):from package.subpackage import module)。
相对导入(relative import)
位于同一包中的不同子包和模块,可以通过前缀.标识存在调用关系的包/模块之间的路径依赖关系并进行相对调用。示例:

同层目录的模块:from . import module;
模块位于同层包内部(不存在子包):from .package import module;
模块位于同层包内部(存在子包):from .packge.subpackge import module;
模块位于上一层级目录:将以上语句的前缀进行替换 from . -> from ..,以此类推。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值