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

这里有什么我遗漏的吗?


当前回答

您可以使用from pkg.components.core导入GameLoopEvents,例如,我使用pycharm,下面是我的项目结构图,我只是从根包导入,然后就可以了:

其他回答

对你没有把它当作一个包。

python -m pkg.tests.core_test

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

$$ py.test

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

from ..components.core import GameLoopEvents

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

由于您已经将所有内容标记为模块,因此如果您作为python模块启动,则无需使用相对引用。

而不是

from ..components.core import GameLoopEvents

仅仅

from pkg.components.core import GameLoopEvents

当您从pkg的父级运行时,请使用以下命令

python -m pkg.tests.core_test

我也遇到过类似的问题,作为一名软件工程师,我认为这里提出的一些解决方案并不理想。如果您想要相对导入,则不应尝试/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 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