我试图遵循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也无法工作”和“从相对路径导入模块”,但它们都没有帮助。

这里有什么我遗漏的吗?


当前回答

我的快速解决方案是将目录添加到路径:

import sys
sys.path.insert(0, '../components/')

其他回答

如果您的用例是用于运行测试的,并且与之吻合,那么您可以执行以下操作。不要将测试脚本作为python core_test.py运行,而是使用诸如pytest之类的测试框架。然后在命令行上输入

$$ py.test

这将在您的目录中运行测试。这解决了@BrenBarn指出的__name__是__main__的问题。接下来,将一个空__init__.py文件放入测试目录,这将使测试目录成为包的一部分。那你就可以

from ..components.core import GameLoopEvents

然而,如果您将测试脚本作为主程序运行,那么事情将再次失败。所以只需要使用测试运行器。也许这也适用于其他测试者,比如鼻测试,但我没有检查过。希望这有帮助。

我的快速解决方案是将目录添加到路径:

import sys
sys.path.insert(0, '../components/')

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

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

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

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

import file2

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

问题在于您的测试方法,

您尝试了python core_test.py

那么你会得到这个错误ValueError:尝试在非包中进行相对导入

原因:您正在从非包源测试您的包。

所以从包源测试模块。

如果这是您的项目结构,

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

cd软件包

python -m tests.core_test # dont use .py

或从外部pkg/

python -m pkg.tests.core_test

仅有一个的如果要从同一目录中的文件夹导入。每后退一步,再加一步。

hi/
  hello.py
how.py

在how.py中

from .hi import hello

如果您想从hello.py导入how

from .. import how

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中的相对导入,了解详细说明以及如何完成。