这里似乎已经有了一些关于python 3中相对导入的问题,但在浏览了许多之后,我仍然没有找到我的问题的答案。 问题来了。

我有一个如下所示的包

package/
   __init__.py
   A/
      __init__.py
      foo.py
   test_A/
      __init__.py
      test.py

我在test.py中有一行:

from ..A import foo

现在,我在包的文件夹,我运行

python -m test_A.test

我收到消息

"ValueError: attempted relative import beyond top-level package"

但是如果我在包的父文件夹中,例如,我运行:

cd ..
python -m package.test_A.test

一切都很好。

现在我的问题是: 当我在包的文件夹中,我运行test_A子包中的模块作为test_A。测试,根据我的理解,..A只上升了一层,仍然在包文件夹中,为什么它给出消息说在顶层包之外。导致此错误消息的确切原因是什么?


当前回答

import sys
sys.path.append("..") # Adds higher directory to python modules path.

试试这个。 为我工作。

其他回答

package/
   __init__.py
   A/
      __init__.py
      foo.py
   test_A/
      __init__.py
      test.py

在A/__init__.py中导入foo:


from .foo import foo

当从test_A/导入A/时


import sys, os
sys.path.append(os.path.abspath('../A'))
# then import foo
import foo

假设: 如果您在包目录中,则A和test_A是单独的包。

结论: ..只允许在包中导入。

进一步指出: 如果您想强制包可以放置在sys.path中的任何路径上,那么使相对导入仅在包中可用是很有用的。

编辑:

我是唯一一个认为这很疯狂的人吗?为什么当前的工作目录不被认为是一个包?——Multihunter

当前工作目录通常位于sys.path中。所有文件都是可导入的。这是自Python 2以来的行为,当时包还不存在。将运行目录作为一个包将允许以“import a”和“import a”的方式导入模块,这将是两个不同的模块。也许这是需要考虑的不一致性。

import sys
sys.path.append("..") # Adds higher directory to python modules path.

试试这个。 为我工作。

这实际上比其他答案要简单得多。

TL;DR:直接导入A,而不是尝试相对导入。

当前工作目录不是包,除非您从另一个文件夹导入文件夹包。因此,如果您打算将包导入其他应用程序,那么包的行为将正常工作。不管用的是测试…

在不改变目录结构的情况下,只需要改变test.py导入foo.py的方式。

from A import foo

现在运行python -m test_A。test将在没有ImportError的情况下运行。

为什么会这样?

当前工作目录不是包,但它被添加到路径中。因此可以直接导入文件夹A及其内容。这是同样的原因,你可以导入任何其他包,你已经安装…它们都包含在你的路径中。

只需移除…在test.py 对我来说,pytest很好地解决了这个问题 例子:

from A import foo