从__init__.py文件进行相对导入会引发错误

10

我正在使用一位同事提供的模板,作为 Python 新手,我可能会错过一些非常显而易见的东西。

主目录有一个 init 文件,其中包含一个我需要的模块,用于生成错误的主 Python 文件。

同事使用了:

from . import X

当X是模块时,但当我将其(以及一个填充了init文件的模块)复制到自己的目录中时,它生成以下错误:

ValueError: 尝试在非包中进行相对导入

从Google和SO中我得知这很正常和合理,所以我想知道,作为一个新手,我错过了什么。


可能是重复的问题:即使有__init__.py,仍在非包中尝试相对导入 - Ferdinand Beyer
在那个建议中,他是从一个标准的.py文件中提取的。我的问题是关于从__init__.py文件中提取。 - thewellis
但是你的问题有相同的原因。我希望我的答案能够阐明你出错的原因。 - Ferdinand Beyer
1个回答

22

你需要了解Python如何处理模块。

当你使用脚本启动解释器时,该脚本将成为主模块,并具有相应的名称__main__

使用import时,其他模块会在搜索路径中查找,你也可以使用sys.path访问(和更改)它。 sys.path的第一个条目通常为空,并表示当前目录。

如果搜索路径内的一个目录包含一个__init__.py文件,则该目录是一个包。

现在,当您在包含__init__.py文件的目录中执行脚本时,此脚本将成为__main__,并且该目录不被视为包,因为它不在sys.path中!

例如,考虑以下目录布局:

root/
    pkg/
        __init__.py
        b.py
        c.py
    a.py

当您从root/目录运行python a.py时,您可以导入pkg/并在该包内使用相对导入(例如,在b.py__init__.py中使用from . import c)。

当您从pkg目录运行python b.py时,您无法使用相对导入,因为Python不将pkg识别为包:它不在sys.path中。 对于Python来说,pkg是一个普通目录,无论其是否包含__init__.pyc.py的完全限定名称只是c,而不是pkg.c,因此相对导入from . import c将不起作用。


1
我想我明白了。由于相对导入的使用仅限于文件夹,因此它会生成错误,因为引用有点循环。这很奇怪,因为我的同事在他的脚本中一直使用这种策略。他编写的大部分代码看起来相当合乎逻辑和严密,也许他有一个Jenkins扩展或其他解析器。 - thewellis
__init__.py 文件在 Python 3.3+ 中已不再需要。 - cambunctious

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接