问题描述

近日在尝试引用其他文件的代码时,遇到了错误: ImportError: attempted relative import with no known parent package.

问题大致是这样的:我想在 code2.py 中引用 code1.py 的函数,如 from ..folder1.code1 import xxx,运行 code2.py 时出现错误。

root
├── folder1
│ └── code1.py
├── folder2
│ └── code2.py
└── main.py

太长不看版

如果你要在 code2.py 中引用 code1.py 的函数,那么可以:

  • 改变文件结构,考虑在 main.py 中调用,运行 main.py
  • code2.py 中增加 root 的位置到搜索路径 sys.path.append, 代码使用 from folder1.code1 import xxx
  • -m 选项运行: python -m root.folder2.code2,代码可以使用 from folder1.code1 import xxxfrom ..folder1.code1 import xxx [我认为这是最优解!]

详细解释

如果对导入的概念不是很理解的话,可能会遇到:

  • ModuleNotFoundError: No module named 'xxx'
  • ImportError: attempted relative import with no known parent package

首先明确两种导入方法:

  1. from xxx import yyy 则是从已知的模块导入
  2. “relative import” 即 from .xxx import yyy,根据从当前文件的相对路径导入。

第一种方法

具体可参考官方文档 the-module-search-path

仅适用于模块(文件夹)或脚本(文件)存在于搜索路径中,导入时,Python 解释器会首先搜索内置模块,如果没有,则去以下三个位置搜索:

  1. 当前文件所在目录
  2. 环境变量 PYTHONPATH 指定的目录
  3. Python 默认的安装目录

可以查看 sys.path,显然,当前运行脚本所在的文件夹被放在了搜索路径的首位,因此该文件夹下的所有内容均可被引入。

import sys
print(sys.path)
# ['/.../path-to-this-folder', '/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '/home/thor/.local/lib/python3.10/site-packages', '/usr/local/lib/python3.10/dist-packages', '/usr/lib/python3/dist-packages']

要解决开头提出的问题,即引入其他文件夹下的内容,可以把 root 的位置添加到搜索路径中:(好吧,这样很不优雅……)

import sys
sys.path.join("/path/to/root") # 用绝对路径,需要从根目录开始
sys.path.join("..") # 用相对路径,但是命令行当前位置不能出错 from folder1.code1 import xxx

可以参考这段代码[1]

if __package__:
from .. import config
else:
sys.path.append(os.dirname(__file__) + '/..')
import config

第二种方法

具体可参考官方文档 packages

需要明确的是,这种方法只适用于 package 内部!

当你把 code2.py 作为脚本运行时,即 python code2.py,此时 python 并不会认为它属于某一个 package, 即使存在 __init__.py。可以 print(__package__) 进行验证,作为脚本运行时为 None,否则则应该为 xxx.yyy 的形式[1:1]

(网络上有很多地方都说添加 __init__.py 就可以解决问题,但事实是并不会 ,在我的测试中,在本文提到的所有的解决方法中,添加 __init__.py 与否似乎不会带来什么影响。)

因此,开头描述的问题中,要使用相对导入的形式在 code2.py 中引用 code1.py 的代码,必须使用:

python -m root.folder1.code1
  • 这里把 root 及其内部当作一个完整的 package,而 package 内的脚本可以使用相对导入互相引用。
  • 这里不带 .py 后缀。
  • 不可以为 python -m folder1.code1,此时把 folder1 及其内部当作一个完整的 package, 无法引用到以外的内容,会遇到 ImportError: attempted relative import beyond top-level package

除了命令行调用时进行调整,在脚本中 import 也是一样的道理:

newroot
├── root
│   ├── folder1
│   │   └── code1.py
│   ├── folder2
│   │   └── code2.py
│   └── main.py
└── upper_main.py
  • upper_main.py 中添加 from root.folder2 import code2 并运行时,它会把 root 当作一个包,此时code2.py中的 from ..folder1.code1 import xxx 可以正常执行
  • main.py 中添加 import folder2.code2 并运行时,它会把 folder2 当作一个包,此时 code2.py 中的 from .xx import 可以正常执行,而 from ..folder1.code1 import xxx 会遇到 ImportError: attempted relative import beyond top-level package.

其他

说明:

  • 这里仅说明我尝试成功得出的经验,不排除有其他正确做法。
  • 我还看到过类似 code2.py 中有 from folder1 import code1 这种做法,没有测试过其适用条件,不过模块内部感觉使用相对引用比较好。

其他参考资料:


  1. 3 Best Solutions For "ImportError: attempted relative import with no known parent package" [2021 Updated]

Python 引用问题 - ImportError: attempted relative import with no known parent package的更多相关文章

  1. Python工程:ImportError: attempted relative import with no known parent package

    Python工程:ImportError: attempted relative import with no known parent package 解决方法: 1.对每个目录创建的时候都选择创建 ...

  2. 执行代码出现ImportError:attempted relative import with no known parent package

    前言 在这篇文章中,我将会解析 ImportError: attempted relative import with no known parent package 这个异常的原因.当你在运行的py ...

  3. 执行文件异常报错:ImportError: attempted relative import with no known parent package

    这个问题困扰了我很久了,网上的解决方法都很一致,找来找去都是一样的解决方法,在导入包的文件和执行文件加入 1 print('__file__={0:<35} | __name__={1:< ...

  4. ImportError: attempted relative import with no known parent package

    或者检查所导包是否存在__init__.py文件,没有则添加上即可使当前文件夹变为包.

  5. python相对包导入报“Attempted relative import in non-package”错误

    文章是从stackoverflow翻译过来的,原文地址:Relative imports for the billionth time 本文要在原理上解决  python当中相对包导入出现的问题. 问 ...

  6. Python ValueError: Attempted relative import in non-package Relative import相对引用 错误

    包含相对路径import的python脚本不能直接运行,只能作为module被引用. 例如 from . import mod1 有这样代码的文件只能最为moulule为不能直接运行.相对路径就是相对 ...

  7. python:Attempted relative import in non-package

    problem:Attempted relative import in non-package 所谓相对路径其实就是相对于当前module的路径,但如果直接执行脚本,这个module的name就是“ ...

  8. Python 相对导入attempted relative import beyond top-level package

    ValueError: attempted relative import beyond top-level package 假设有如下层次包目录 project/ __init__.py mypac ...

  9. ValueError: Attempted relative import in non-package

    执行:python deom/scripts/populate.py ValueError: Attempted relative import in non-package solve:python ...

  10. Python导入自定义类时显示错误:attempted relative import beyond top-level package

    显示这个错误可能有两个原因: 1.文件夹中没有包含__init__.py文件,该文件可以为空,但必须存在该文件. 2.把该文件当成主函数入口,该文件所在文件夹不能被解释器视作package,所以可能导 ...

随机推荐

  1. layUI之树状表格异步加载组件treetableAsync.js(基于treetable.js)

    目录 概述 1. 使用说明 2. 使用需知 2.1 本组件依赖于treetable.js[重中之重] 2.2 本组件基于layUIAdmin进行使用 2.3 本组件的方法支持treetable.js的 ...

  2. Sql批量替换字段字符,Sql批量替换多字段字符,Sql替换字符

    update phome_ecms_news_check set filename= replace(filename,'Under4-',''); update phome_ecms_news_ch ...

  3. 开源后台管理系统解决方案 boot-admin 简介

    介绍 boot-admin 是一款采用前后端分离架构模式的后台管理框架.系统提炼自实际项目,兼具RuoYi-Vue前端分离版和Ruoyi-Cloud微服务版功能与技术特点. boot-admin 既有 ...

  4. Awesome GPT 来了!

    大家好!我是韩老师. GPT, ChatGPT, OpenAI, LLM(大语言模型)等等技术的出现与应用,改变了许多的行业和人. 长期来看,类 GPT 的技术会对整个世界有着持续的改变. 我们几乎每 ...

  5. Java 新的生态型应用开发框架,Solon v2.2.13 发布

    Java 新的生态型应用开发框架,Solon :更快.更小.更简单.从零开始构建,有自己的标准规范与开放生态: 150多个生态插件,可以满足各种场景开发 大量的国产框架适配,可以为应用软件国产化提供更 ...

  6. ffmpeg音视频基础学习

    ffmpeg音视频基础学习 从去年开始了解音视频,中间也由于项目的需要,学习过ffmpeg.live555.以及QTAV框架,一直没总结过,现在大致总结下音视频中的常见词汇,后续慢慢更新添加!博客也会 ...

  7. 禁用Chrome浏览器Websocket

    前言:最近遇到关于Websocket的相关测试,推荐一个禁用Chrome浏览器Websocket的扩展插件 一.下载使用 1.https://github.com/arthepsy/chrome-di ...

  8. 使用NineData定制企业级数据库规范

    1. 为什么需要数据库规范? 在企业级应用中,数据库是非常重要的一部分,它们存储着公司的核心数据,包括客户信息.订单.产品信息等等.如果这些数据没有得到妥善的管理,那么就会导致数据不一致.数据丢失.数 ...

  9. 2021-10-18:乘积最大子数组。给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。力扣152。

    2021-10-18:乘积最大子数组.给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积.力扣152. 福大大 答案2021-1 ...

  10. 原来.NET写的Linux桌面这么好看?

    如何使用Blazor在Linux平台下运行Desktop程序 本文将讲解如何使用Blazor运行跨平台应用,应用到的技术有以下几点 Blazor Masa Blazor Photino.Blazor ...