【问题标题】:Importing Python class from sibling directory从同级目录导入 Python 类
【发布时间】:2019-10-01 21:33:32
【问题描述】:

/VM/repo/project 中我的目录结构是:

__init__.py

scripts/
      getSomething.py
      __init__.py

classes/
      project.py
      db.py
      __init__.py

getSomething.py

from ..classes import project
from ..classes import db

项目.py

class PROJECT:
def __init__(self):
    stuff

db.py

class DB:
def __init__(self):
    stuff

当我尝试运行时

python getSomething.py

我得到了错误

回溯(最近一次通话最后一次):

中的文件“scripts/getSomething.py”,第 4 行 从 ..classes 导入项目
ValueError:尝试在非包中进行相对导入

我在这里缺少什么?

【问题讨论】:

    标签: python import module package relative-import


    【解决方案1】:

    如错误中所述,您将 getSomething 作为主模块运行。但是当您不在包中时,您不能进行包相对导入。主模块从不在包中。因此,如果您要将 getSomething 作为包的一部分导入...:

    # /VM/repo/main.py
    from project.scripts import getSomething
    

    那么你就不会有导入错误了。


    或许快速讨论一下 Python 模块和包会有所帮助。通常,包含 python 源代码并具有 .py 扩展名的文件是一个模块。通常,该模块的名称是文件的名称(无扩展名),但如果您直接运行它,该模块的名称是'__main__'。到目前为止,这一切都是众所周知的并且有据可查。要导入模块,您只需执行import module 或import package.module 等等。最后一条 import 语句指的是我们现在要讨论的其他东西(“包”)......

    包是您可以导入的目录。许多目录无法导入(例如,它们可能没有 python 源文件——模块——在其中)。所以为了解决这个歧义,还需要目录有一个__init__.py 文件。当您在文件系统上导入目录时,python 实际上会导入 __init__.py 模块并根据 __init__.py 中的内容创建关联的包(如果有的话)。

    将所有这些放在一起说明为什么在具有__init__.py 的目录中执行文件不足以让python 将模块视为包的一部分。首先,模块的名称是__main__,而不是package.filename_sans_extension。其次,包的创建不仅取决于文件系统结构,还取决于目录(因此 __init__.py 是否被实际导入)。

    您可能会问自己“他们为什么要这样设计?”事实上,我有时也会问自己同样的问题。我认为原因是语言设计者希望为包提供某些保证。包应该是为特定目的而设计的事物单元。它不应该是一个脚本孤岛,通过一些随意的__init__.py 文件获得在文件系统中遍历以找到他们需要的其他模块的能力。如果某些东西被设计为作为主模块运行,那么它可能不应该是包的一部分。相反,它应该是一个单独的模块来导入包并依赖它。

    【讨论】:

    • 好的,有几件事:我的印象是,将__init__.py 添加到每个目录实际上将这些目录定义为一个包?我可能对这里的包有一个基本的误解。为什么主模块从不在包中?其次:我的目标是在 cron 上运行脚本。有没有办法直接将类导入脚本?创建另一个文件main.py 再上一层对我来说似乎是不必要的复杂化。
    • @ShaneOH -- 我已经尝试(尽我所能)编辑我的答案,希望能消除任何歧义......我希望它会有所帮助。
    • 谢谢,原始答案和编辑都非常有帮助。所以我有最后一个问题:如果我想保留这个目录结构并直接运行脚本,作为主要模块怎么办?好吧,它们不需要成为软件包的一部分。如何将 /classes 模块导入同级文件夹中的主模块?然后我要从 /scripts 和 /project 中删除 __init__.py 吗?
    • 您可以将path/to/project 添加到您的PYTHONPATH。那么你的脚本应该能够从文件系统中的任何位置import project.classes.xyz....
    • 知道了。不幸的是,这一切看起来如此不直观,但我能理解你描述的优点。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    • 2012-05-03
    • 2019-06-19
    相关资源
    最近更新 更多