我试图遵循PEP 328,其目录结构如下:

pkg/
  __init__.py
  components/
    core.py
    __init__.py
  tests/
    core_test.py
    __init__.py

在core_test.py中,我有以下import语句

from ..components.core import GameLoopEvents

然而,当我运行时,我得到以下错误:

tests$ python core_test.py 
Traceback (most recent call last):
  File "core_test.py", line 3, in <module>
    from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package

四处搜索,我发现“相对路径即使使用__init__.py也无法工作”和“从相对路径导入模块”,但它们都没有帮助。

这里有什么我遗漏的吗?


当前回答

在core_test.py中,执行以下操作:

import sys
sys.path.append('../components')
from core import GameLoopEvents

其他回答

如果有人在寻找变通办法,我偶然发现了一个。这里有一点上下文。我想测试我在文件中的一种方法。当我从内部运行时

if __name__ == "__main__":

它总是抱怨相对进口。我尝试应用上述解决方案,但失败了,因为有许多嵌套文件,每个文件都有多个导入。

这是我所做的。我刚刚创建了一个启动器,一个外部程序,可以导入必要的方法并调用它们。尽管这不是一个很好的解决方案,但它还是有效的。

如果您的项目结构如下所示:

   project
     |
     | --- module1
     |      |
     |      file1.py
     |
     |-----module2
     |     |
     |     file2.py

您将从file2.py中导入file1.py,您可以在file2.py中执行此操作:

import sys
sys.path.append('.')

import file2

我仍然不知道为什么和怎么做,但这对我有用。

详细阐述伊格纳西奥·巴斯克斯·阿布拉姆斯的回答:

Python导入机制相对于当前文件的__name__工作。当您直接执行文件时,它没有通常的名称,而是使用“__main__”作为其名称。因此相对进口不起作用。

正如Igancio所建议的,您可以使用-m选项执行它。如果您的包中有一部分要作为脚本运行,那么还可以使用__package__属性告诉该文件在包层次结构中应该具有什么名称。

看见http://www.python.org/dev/peps/pep-0366/详细信息。

我也遇到过类似的问题,作为一名软件工程师,我认为这里提出的一些解决方案并不理想。如果您想要相对导入,则不应尝试/except,然后有时进行绝对导入。此外,要运行程序,您不必更改sys.path。

此外,程序应该始终运行,独立于当前的工作目录和启动方式。

因此,我创建了一个新的实验导入库:ultraimport它允许基于文件系统的导入,无论您如何运行代码。

从最初的问题中,您可以将core_test.py更改为

import ultraimport
GameLoopEvents = ultraimport('__dir__/../components/core.py', 'GameLoopEvents')
print(GameLoopEvents)

无论您如何运行测试,它都会找到它。

$ python -m tests.core_test
<class 'core.GameLoopEvents'>
 python ./tests/core_test.py 
<class 'core.GameLoopEvents'>

我还将此示例放入git repo的examples文件夹中。

由于图书馆是实验性的,我对反馈感兴趣。它对我有效,但尚未得到广泛测试。

python<main模块>.py不适用于相对导入

问题是当您从命令行运行__main__模块时,相对导入不起作用

python <main_module>.py

PEP 338中有明确规定。

2.5b1的发布显示了这个PEP和PEP328之间令人惊讶的交互(尽管现在回想起来很明显)——显式的相对导入在主模块中不起作用。这是因为相对导入依赖__name__来确定当前模块在包层次结构中的位置。在主模块中,__name__的值总是'__main__',因此显式相对导入总是失败(因为它们只适用于包内的模块)。

原因

Python Bug Tracker Issue1510172:绝对/相对导入不起作用?

这个问题实际上并不是-m开关独有的。问题是相对导入基于__name__,并且在主模块中,__name__始终具有__main__值。因此,相对导入当前无法从应用程序的主模块正常工作,因为主模块不知道它在Python模块名称空间中的真正位置(这至少在理论上对于通过-m开关执行的主模块是可以修复的,但直接执行的文件和交互式解释器完全不走运)。

要进一步了解,请参阅Python3中的相对导入,了解详细说明以及如何完成。