Relative imports within a module

12 浏览
0 Comments

Relative imports within a module

想象一下这个目录结构:

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

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

我尝试了from ..sub2 import mod2,但是我得到了一个“在非包中尝试相对导入”的错误提示。

我谷歌搜索了一下,但只找到了“sys.path操纵”的hack方法。难道没有干净的方法吗?


编辑:我所有的__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