【问题标题】:ValueError: attempted relative import beyond top-level package pythonValueError:尝试相对导入超出顶级包 python
【发布时间】:2021-10-03 20:40:58
【问题描述】:

我有一个这样的目录结构。

Chatbot/
   utils/
     abc.py
   projects/
      proj1/
        utils/
          __init__.py
          data_process.py
        components/
          class1.py

我的结构中有两个utils 文件夹,一个在顶层,一个在我的项目文件夹中。

现在我想在class1.py 中导入data_process.py 文件。所以我就这样尝试了

from utils.data_process import DataProcess

但它引用了顶级 utils 文件夹,甚至 VSCode 也无法识别它。我尝试在utils 文件夹中创建__init__.py 文件,但仍然无法正常工作。

我尝试使用空的__init__.py,然后放置此内容

from . import data_process
__all__ = ['data_proces']

然后

from .data_process import DataPreprocess
__all__ = ['DataPreprocess']

然后我尝试了

from ..utils.data_process import DataProcess

VSCode 正在识别这一点,但它不工作并抛出错误

ValueError: attempted relative import beyond top-level package

即使我尝试将名称 utils 更改为其他名称,但仍然是同样的问题

我该如何解决这个问题?

【问题讨论】:

    标签: python importerror


    【解决方案1】:

    sys.path 是 Python 搜索模块和包的地方,它按顺序

    所以你可以把...../proj1/放在列表的开头,当python开始搜索时,它会首先在该路径中找到utils文件夹!

    import sys
    sys.path.insert(0, r'...../proj1/')
    

    但这会导致另一个问题,python总是先在那个文件夹中找到utils,这不是你想要的。

    解决方案编号 1

    绝对导入:

    from Chatbot.projects.proj1.utils.data_process import DataProcess
    

    解决方案编号 2

    使用@Mr.Hobo 提到的相对导入。

    【讨论】:

    • 是的,sys.path 方法很好.. 但是每次都提起来很乏味... 你可以使用PYTHONPATH tutorial in windows 解决这个问题
    • @Mr.Hobo emm 实际上它们(PYTHONPATH 或 sys.path)都引起了问题。主要问题是我们有两个名字叫utils!无论哪个路径在 sys.path 中首先可以访问,utils 都会首先遇到,无论我们在哪里。所以更好的解决方案是使用我提到的绝对导入。
    • 请检查更新后的答案。我能够轻松地完成这个项目,没有任何问题。我还添加了与此项目结构相关的个人 GitHub 项目帐户的链接。
    • @Mr.Hobo 我已经更新了我的答案,并参考了你的相关导入。
    【解决方案2】:

    python 模块由一个名为__init__.py 的特殊文件定义,该文件应存在于所有子目录中。因此,您的文件结构将是:

    Chatbot/
       __init__.py
       utils/
         __init__.py
         abc.py
       projects/
          __init__.py
          proj1/
            __init__.py
            utils/
              __init__.py
              data_process.py
            components/
              __init__.py
              class1.py
              class2.py
    

    现在,您可以像这样进行相对导入:

    • 使用. 在同一目录中导入某些内容。示例:
    # file Chatbot/projects/proj1/components/class2.py
    from .class1 import *
    
    • 同理,.. 表示两级,... 表示三级,以此类推!

    例如:

    # file Chatbot/projects/proj1/components/class2.py
    from ..utils.data_process import * # import from data_process.py
    # there will be four "." earlier I made a counting mistake
    from ....utils.abc import * # import something from abc.py
    

    编码约定

    在编写 python 模块/包时,您可能需要关注PEP8 Convention

    此外,我相信您正在尝试使用您的包Chatbot 做不同的项目,对吗?然后,将PYTHONPATH 设置为Chatbot 并执行所有项目并单独导入是一个很好的做法。

    编辑:上传虚拟文件

    即使使用两个utils 目录,我也能够无缝地处理这个项目。项目结构:

    main 文件及其输出:

    # file main.py
    from chatbot.utils.abc import hello as a1
    from chatbot.projects.proj1.components.class1 import super_hello
    from chatbot.projects.proj1.utils.data_process import hello as b1
    
    print(a1(), b1())
    print(super_hello())
    

    同样,如果您在PYTHONPATH 下有chatbot,您可以从设备的任何位置调用该项目。

    代码详情和文件请added into my github account了解详情。

    【讨论】:

    • 聊天机器人外部项目使用从内部项目创建的模型,这就是它包含项目文件夹的原因。项目文件夹包含独立项目,但其输出用于顶级聊天机器人项目。
    • 我需要在环境变量中提及 PYTHONPTH 吗?
    • 我需要将 init.py 文件添加到每个文件夹,甚至不是包?
    • 我不明白你提到的外部/内部项目。您可能想研究这些以明确概念:Python Packaging - [1, 2];导入 UD 包 - [1, 2]
    • 如果你正在创建一个chatbot 并且你想在不同的代码中使用这个python 包,那么这不应该是你设计代码的方式。相反,您应该使用@SorousH Bakhtiary 提到的PYTHONPATHsys.path
    猜你喜欢
    • 2016-05-12
    • 2020-04-06
    • 1970-01-01
    • 2018-12-05
    • 2020-11-03
    • 2017-02-22
    • 1970-01-01
    相关资源
    最近更新 更多