Python 3中的相对导入不起作用

Joh*_*nal 52 python import module

我有以下目录:

mydirectory
??? __init__.py
??? file1.py 
??? file2.py
Run Code Online (Sandbox Code Playgroud)

我有一个在file1.py中定义的函数f.

如果,在file2.py中,我这样做

from .file1 import f
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

SystemError:父模块''未加载,无法执行相对导入

为什么?以及如何使它工作?

Bak*_*riu 42

在包中启动模块作为可执行文件是一种不好的做法.

当您开发某些东西时,您要么构建一个库,该库旨在由其他程序导入,因此允许直接执行其子模块没有多大意义,或者您构建了一个可执行文件,在这种情况下没有理由让它成为一部分一揽子.

这就是setup.py您区分包和脚本的原因.site-packages当脚本将安装在/usr/bin(或类似的位置,具体取决于操作系统)下时,软件包将处于打开状态.

因此我建议使用以下布局:

/
??? mydirectory
|    ??? __init__.py
|    ??? file1.py 
??? file2.py
Run Code Online (Sandbox Code Playgroud)

其中file2.py导入file1.py与任何其他想要使用该库的代码一样mydirectory,具有绝对导入:

from mydirectory.file1 import f
Run Code Online (Sandbox Code Playgroud)

当您setup.py为项目编写脚本时,您只需将其mydirectory列为包和file2.py脚本,一切都会正常工作.无需捣鼓sys.path.

如果由于某种原因,你真的想要实际运行一个包的子模块,那么正确的方法就是使用这个-m开关:

python -m mydirectory.file1
Run Code Online (Sandbox Code Playgroud)

这将加载整个包,然后将该模块作为脚本执行,从而允许相对导入成功.

我本人避免这样做.还因为很多人甚至不知道你可以做到这一点,并最终会得到与你相同的错误,并认为包破坏了.


关于当前接受的答案,该答案表示您应该使用隐式相对导入,from file1 import f因为它可以工作,因为它们位于同一目录中:

这是错的!

  • 不适用于不允许隐式相对导入的python3,如果你碰巧安装了一个file1模块肯定会破坏(因为它将导入而不是你的模块!).
  • 即使它有效,file1也不会将其视为mydirectory包装的一部分.这关系.

    例如,如果file1使用pickle,则包的名称对于正确加载/卸载数据很重要.


mrK*_*ley 24

因为file1并且file2在同一目录中,您甚至不需要拥有__init__.py文件.如果你要扩大规模,那就把它放在那里.

要在同一目录中的文件中导入内容,只需这样做

from file1 import f

即,您不需要执行相对路径,.file1因为它们位于同一目录中.

如果您将运行整个应用程序的主要功能,脚本或其他内容位于另一个目录中,那么您将必须使所有内容相对于正在执行的任何位置.

  • 这假设PYTHONPATH中没有其他`file1`. (6认同)

sta*_*alk 20

启动python源文件时,禁止使用相对导入导入当前包中的另一个文件.

文档中说:

请注意,相对导入基于当前模块的名称.由于主模块的名称始终为"__main__",因此用作Python应用程序主模块的模块必须始终使用绝对导入.

因此,正如@mrKelley所说,在这种情况下你需要使用绝对导入.