这里似乎已经有了一些关于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只上升了一层,仍然在包文件夹中,为什么它给出消息说在顶层包之外。导致此错误消息的确切原因是什么?
编辑:这个问题在其他问题中有更好/更连贯的答案:
兄弟包导入
第10亿次相对进口
Why doesn't it work? It's because python doesn't record where a package was loaded from. So when you do python -m test_A.test, it basically just discards the knowledge that test_A.test is actually stored in package (i.e. package is not considered a package). Attempting from ..A import foo is trying to access information it doesn't have any more (i.e. sibling directories of a loaded location). It's conceptually similar to allowing from ..os import path in a file in math. This would be bad because you want the packages to be distinct. If they need to use something from another package, then they should refer to them globally with from os import path and let python work out where that is with $PATH and $PYTHONPATH.
当你使用python -m package.test_A。测试,然后使用from ..import foo可以很好地解决问题,因为它跟踪了包中的内容,而你只是访问了加载位置的子目录。
为什么python不认为当前工作目录是一个包?不知道,但天哪,这将是有用的。
这些解决方案在3.6中都不适合我,文件夹结构如下:
package1/
subpackage1/
module1.py
package2/
subpackage2/
module2.py
我的目标是从module1导入到module2。奇怪的是,最后对我有用的是:
import sys
sys.path.append(".")
注意单点解决方案,而不是迄今为止提到的两点解决方案。
编辑:以下内容帮助我澄清了这一点:
import os
print (os.getcwd())
在我的例子中,工作目录(出乎意料地)是项目的根目录。
我对这个问题的理解是这样的:
[案例1]当你开始一个绝对导入
python -m test_A.test
or
import test_A.test
or
from test_A import test
你实际上是将导入锚设置为test_A,换句话说,顶级包是test_A。当我们有test。py do from。一个导入xxx,你正在从锚转义,而Python不允许这样做。
[案例2]当你这样做的时候
python -m package.test_A.test
or
from package.test_A import test
你的锚变成了包,所以包/test_A/test.py从…导入xxx不会转义锚(仍然在包文件夹内),Python很乐意接受这一点。
简而言之:
Absolute-import改变当前锚(=重新定义什么是顶级包);
相对导入不会改变锚,而是限定在锚上。
此外,我们可以使用全限定模块名(FQMN)来检查这个问题。
检查每种情况下的FQMN:
【例2】测试。__name__ = package.test_A.test
(CASE1)测试。__name__ = test_A.test
对于CASE2, an。import xxx将生成一个带有FQMN=package的新模块。Xxx,这个可以接受。
对于CASE1, ..从内部从…import xxx将跳出test_A的起始节点(锚点),这是Python不允许的。
我认为这种“相对导入”的限制是一种相当丑陋的设计,完全违背了Python的格言“简单比复杂好”。