如何在Python中进行相对导入?

22 浏览
0 Comments

如何在Python中进行相对导入?

假设这是目录结构:

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

我正在编写mod1,我需要从mod2导入一些内容。我该怎么做?

我尝试了from ..sub2 import mod2,但是我得到了一个\"Attempted relative import in non-package\"错误。

我在谷歌上搜索,但只找到了\"sys.path操纵\"的技巧。难道没有更简单的方法吗?


编辑:我所有的__init__.py都是空的

编辑2:我试图这样做是因为sub2包含在子包(sub1subX等)中共享的类。

编辑3:我寻找的行为与PEP 366中描述的行为相同(感谢John B)

admin 更改状态以发布 2023年5月24日
0
0 Comments

这是适用于我的解决方案:

我使用相对导入 from ..sub2 import mod2,如果我想运行 mod1.py,那么我需要进入 app 的上级目录,并使用 python -m 开关运行模块,命令如下:python -m app.sub1.mod1

相对导入出现问题的真正原因是,相对导入是通过获取模块的 __name__ 属性来工作的。如果直接运行模块,则 __name__ 被设置为 __main__,它不包含任何关于包结构的信息。这就是 Python 报错相对导入非包错误的原因。

因此,通过使用 -m 开关,您提供了包结构信息给 Python,使其能够成功解析相对导入。

我在进行相对导入时遇到过这个问题很多次。在阅读了所有之前的答案后,我仍然无法找到一种干净的方法来解决它,而无需在所有文件中添加样板代码。(尽管一些评论非常有帮助,感谢 @ncoghlan 和 @XiongChiamiov)

希望这可以帮助那些正在与相对导入问题斗争的人,因为阅读 PEP 真的不好玩。

0
0 Comments

每个人似乎都想告诉你应该做什么,而不只是回答问题。

问题在于,你通过将mod1.py作为解释器的参数来运行模块作为“__main__”。

PEP 328中得知:

相对导入使用模块的__name__属性确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如它设置为“__main__”),则相对导入将被解析为模块是顶层模块,而不管模块实际位于文件系统上的位置。

在Python 2.6中,它们正在添加相对于主模块引用模块的功能。PEP 366描述了这个变化。

更新:根据Nick Coghlan的说法,推荐的替代方法是使用-m开关在包内运行模块。

0