如何修复这些相对导入错误

Zac*_*han 2 python python-import python-3.6

我有这样的文件夹结构,每次尝试使用相对导入时,都会出现错误

\n\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 graphics\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 A\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 grok.py\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 spam.py\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 B\n        \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n        \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 bar.py\n\n\nspam.py/\n    def func():\n        pass\nbar.py/\n    def f():\n        pass\n
Run Code Online (Sandbox Code Playgroud)\n\n

所有这些代码都在 grok.py 中进行了测试:

\n\n
from . import spam\n# ImportError: cannot import name 'spam'\n\nfrom .spam import func\n# ModuleNotFoundError: No module named '__main__.spam'; '__main__'     \nis not a package\n\nfrom ..B import bar\n# ValueError: attempted relative import beyond top-level package\n
Run Code Online (Sandbox Code Playgroud)\n\n

以下代码均不会导致任何错误:

\n\n
from graphics.A import spam\nfrom graphics.A.spam import func\nfrom graphics.B import bar\nfrom graphics.B.bar import f\n
Run Code Online (Sandbox Code Playgroud)\n

Gin*_*pin 5

我认为当你说“在 grok.py 中测试”时,你正在像这样运行它:

\n\n
python3 graphics/A/grok.py\npython3 A/grok.py\npython3 grok.py\n
Run Code Online (Sandbox Code Playgroud)\n\n

来自关于包包内引用的Python 文档,有一条注释说:

\n\n
\n

请注意,相对导入基于当前模块的名称。由于主模块的名称始终为“ __main__”,\n 用作 Python 应用程序主模块的模块\n 必须始终使用绝对导入

\n
\n\n

当您运行 时grok.py,它会被视为主模块,并且仅当您使用绝对导入时导入才会起作用(假设您没有对 进行任何更改sys.path,我们稍后会介绍)。print(__name__)您可以通过将其放在grok.py 的开头来测试,它将打印出“__main__,它将打印出“ ”。

\n\n

如果您在调用您的图形包下有一个单独的 python 文件(例如),您的相对导入实际上将会起作用main.pygrok将会起作用:

\n\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 graphics\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n|   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 main.py     <<---- add this\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 A\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 B\n
Run Code Online (Sandbox Code Playgroud)\n\n

在 中main.py,我们只需导入grok模块:

\n\n
from A import grok\n
Run Code Online (Sandbox Code Playgroud)\n\n

grok.py,让我们测试相对导入:

\n\n
from . import spam\nspam.spam_func()\n\nfrom .spam import spam_func\nspam_func()\n\nfrom B import bar\nbar.bar_func()\n
Run Code Online (Sandbox Code Playgroud)\n\n

spam.py

\n\n
def spam_func():\n    print("spammy")\n
Run Code Online (Sandbox Code Playgroud)\n\n

bar.py

\n\n
def bar_func():\n    print("barry")\n
Run Code Online (Sandbox Code Playgroud)\n\n

当你跑步时main.py

\n\n
graphics$ python3 main.py\nspammy\nspammy\nbarry\n
Run Code Online (Sandbox Code Playgroud)\n\n

您不会收到任何先前的错误。相对导入有效。请注意,要从 导入B,我使用的from Bfrom ..B。这是因为导入路径是从main.py. 您可以通过将其添加到顶部来测试这一点main.py

\n\n
import sys\nprint(sys.path)\n# prints a list, [\'/path/to/graphics/\',...]\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您from ..B这样做,这意味着/path/to/graphics/../当然没有该B模块(因此,您将得到“尝试相对导入超出顶级包”错误)

\n\n
\n\n

现在假设您不想使用单独的程序main.py并且想grok.py直接运行。您可以做的就是手动将包的路径添加graphicssys.path. 然后你可以from Afrom Bgrok.py

\n\n
import sys\nsys.path.append("/full/path/to/graphics/")\n\nfrom A import spam\nspam.spam_func()\n\nfrom B import bar\nbar.bar_func() \n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您想“破解” sys.path,我建议您阅读更多内容sys.path并检查其他相关帖子,这些帖子讨论了添加路径的方法sys.path相关帖子。

\n