为了更好地理解它的工作原理,我正在玩 Python 的导入系统,但我遇到了另一个问题。我有以下结构
pkg/
__init__.py
c.py
d.py
subpkg/
__init__.py
a.py
b.py
在 a.py
我有以下代码:
from . import b
from .. import d
在 c.py
内,我有以下内容:
import subpkg.a
现在我收到以下错误:
ValueError:尝试相对导入超出顶级包
但是为什么?我该如何解决?我正在从 IDLE 运行 c.py
,并且 pkg
应该被视为一个包,因为它具有 __init__.py
文件。
第一个导入工作正常,但以下不起作用:
from .. import d
因为我试图从父包中导入一些东西,但显然我不能,出于某种奇怪的原因。
这让我怀疑自己的精神错乱。
问题源于人们错误地将相对导入作为路径相对而不是相对路径的混淆。
相对导入取决于运行文件的位置。
此 answer 更深入地解释了 Python 模块的实际工作原理,但要进行总结。
当一个文件被加载时,它被赋予一个名字:如果它被加载为顶级脚本(直接运行),它的名字是__main__。如果它作为一个模块加载(带有导入),它的名称是文件名,前面是它所属的任何包/子包的名称,用点分隔 - pkg.subpkg.a 如果你执行 from ..文件名中必须至少有 2 个点。从 ... - 3 个点。
现在是有趣的部分。
如果您直接运行 c.py,则它的名称为 __main__
,而 a.py 具有 subpkg.a
。
根据第二条语句,您必须在 subpkg.a
的名称中至少有 2 个点才能在其中运行 from ..
。
修复
在 pkg 之外创建一个新文件,例如 main.py
pkg/
__init__.py
c.py
d.py
subpkg/
__init__.py
a.py
b.py
main.py
里面 main.py
import pkg.c
如果我们运行 main.py,它会得到名称 __main__
,而 a.py 会得到 pkg.subpkg.a
。根据第二条语句,现在名称中有 2 个点,我们可以执行 from ..
还有一件事。现在 c.py 已作为模块加载,我们必须使用 from 来加载 a.py。
from .subpkg import a
Python 3 改变了导入系统,所以每次你想要一个与你正在工作的模块相关的模块时,你都需要相对导入(除非你弄乱了 PYTHONPATH
或 sys.path
)。
这里正确的用法应该是
from .subpkg import a
当您使用 IDLE 时,您将拥有一个完全不同的环境。因此,您可以将当前位置添加到您的路径中,以便再次导入。
尝试:
sys.path.insert(0, '')
这可能很奇怪,但这是为了更大的利益
PS:如果最后这件事不起作用-我现在没有IDLE环境-可能是因为工作目录设置错误。
试试这个答案:https://stackoverflow.com/a/17361545/754991
我找到了这个解决方案:
#! /usr/bin/env python
import os
import sys
sys.path.append(os.path.realpath('.'))
from d import *
chdir
到不同的目录,它会失败,我相信。
只需在所有文件夹中添加/创建 init.py 文件即可解决问题。
文件夹 1 -文件夹 2 -文件 1.py -文件夹 3 -文件夹 4 -文件 2.py
我想在 file2.py 中使用 file1.py 中存在的一种方法 [基本上向上两层]。所以我在上面的所有文件夹和子文件夹中添加了空的 init.py,并在下面的 file2.py 中使用:-
从文件夹 2.file1 导入 <方法名>
我很感谢最佳答案,但我发现建议的修复有点不满意。这是我的建议:只需将 sys.path.append(".") 添加到您的主文件中。这允许在不更改项目架构的情况下导入第一级包。只需删除以前的 .. 不再需要。
typhon04 有一个很好的描述,帮助我理解了这个问题,但我不同意他在一切之外创建一个虚拟 main.py 的结论。鉴于我们与 c.py 相关,答案似乎是我们不再需要“from ..”,而只需“import d”就足够了。
from .subpkg import a
,我会收到:来自 IDLE 和终端的SystemError: Parent module '' not loaded, cannot perform relative import
...sys.path
上添加pkg
的目录后使用完整的包名称:from pkg import subpkg.a
c.py
(作为主文件),它给了我上面提到的错误。 IDLE 是一个糟糕的 IDE,但它带有 Python?携带一个糟糕的 IDE 的目的是什么?你可以说 IDLE 是一个简单的 IDE,它肯定不是最好的,但理论上它应该可以很好地与 Python 配合使用,否则没有任何意义。from .subpkg import a
没有回答问题。问题是问如何from .. import d
。