【一分钟解决】Python报错ImportError: attempted relative import with no known parent package

文章目录

  • 报错关键词
  • 常见问题汇总及排查
  • 1. 在脚本中使用相对导入
  • 详细解决方案
  • 1. 【看这段基本够了】使用相对导入的时机
  • 2. 【扩展】如果你真的需要在包平级目录以外的位置调用包
  • 参考链接
  • * 扩展:名词解释
  • 脚本(script)
  • 模块(module)
  • 包(package)
  • 绝对导入(absolute import)
  • 相对导入(relative import)

  • 报错关键词

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

  • 常见问题汇总及排查

    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)

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

    1. Python自带或pip安装的包;
    2. Python解释器启动位置同层模块和包;
    3. 人为添加到系统环境变量 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 ..,以此类推。
  • 来源:jaredyam

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【一分钟解决】Python报错ImportError: attempted relative import with no known parent package

    发表评论