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

我有以下目录:

mydirectory
├── __init__.py
├── file1.py 
└── file2.py

我在file1.py中定义了一个函数f。

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

from .file1 import f

我收到以下错误:

SystemError:父模块“”未加载,无法执行相对   进口

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

John Smith Optional asked 2020-01-14T15:55:32Z
4个解决方案
42 votes

将软件包内部的模块作为可执行文件启动是一种不好的做法。

当您开发某些东西时,您要么建立一个打算由其他程序导入的库,所以直接允许执行其子模块没有多大意义,或者您建立了一个可执行文件,在这种情况下,没有理由将其分成一部分 一个包装。

这就是为什么在file1中区分软件包和脚本的原因。 程序包将在pickle下,而脚本将在file2.py(或类似位置,取决于操作系统)下安装。

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

/
├── mydirectory
|    ├── __init__.py
|    ├── file1.py 
└── file2.py

其中file1pickle导入为要使用库file2.py的任何其他代码,并使用绝对导入:

from mydirectory.file1 import f

当您为项目编写file1脚本时,只需将pickle作为程序包列出,将file2.py作为脚本列出,一切便会正常进行。 无需摆弄sys.path

如果出于某种原因您确实想真正运行程序包的子模块,则执行此操作的正确方法是使用file1开关:

python -m mydirectory.file1

这将加载整个程序包,然后将其作为脚本执行,从而允许相对导入成功。

我个人避免这样做。 另外,因为很多人甚至不知道您可以执行此操作,并且最终会收到与您相同的错误,并认为程序包已损坏。


关于当前接受的答案,它说您应该只使用一个隐式相对导入file1,因为它可以在同一个目录中工作:

错了!

  • 它在不允许隐式相对导入的python3中不起作用,并且如果您恰好安装了file1模块(肯定会导入而不是模块!),肯定会中断。
  • 即使工作正常,file1也不会被视为pickle软件包的一部分。 这很重要。

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

Bakuriu answered 2020-01-14T15:57:32Z
24 votes

由于.file1file2位于同一目录中,因此您甚至都不需要__init__.py文件。 如果您要扩大规模,请留在那里。

要将某文件导入同一目录中的文件,只需执行以下操作

.file1

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

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

mrKelley answered 2020-01-14T15:56:12Z
20 votes

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

在文档中说:

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

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

stalk answered 2020-01-14T15:58:05Z
0 votes
myproject/

mypackage
├── __init__.py
├── file1.py
├── file2.py 
└── file3.py

mymainscript.py

从一个文件导入到另一个文件的示例

#file1.py
from myproject import file2
from myproject.file3 import MyClass

将包示例导入主脚本

#mymainscript.py
import mypackage

[https://docs.python.org/3/tutorial/modules.html#packages]

[https://docs.python.org/3/reference/import.html#regular-packages]

[https://docs.python.org/3/reference/simple_stmts.html#the-import-statement]

[https://docs.python.org/3/glossary.html#term-import-path]

变量sys.path是一个字符串列表,用于确定解释器的模块搜索路径。 它将初始化为从环境变量PYTHONPATH提取的默认路径,或者如果未设置PYTHONPATH则从内置默认值初始化。 您可以使用标准列表操作对其进行修改:

import sys
sys.path.append('/ufs/guido/lib/python')
sys.path.insert(0, '/ufs/guido/myhaxxlib/python')

在开头插入它的好处是,在命名冲突的情况下,可以确保先搜索其他路径(甚至是内置路径)。

The Demz answered 2020-01-14T15:58:57Z
translate from https://stackoverflow.com:/questions/16637428/relative-import-in-python-3-is-not-working