Python模块的绝对和显式相对导入


85

我想知道在Python应用程序中导入包的首选方法。我有一个这样的包结构:

project.app1.models
project.app1.views
project.app2.models

project.app1.views进口project.app1.modelsproject.app2.models。我想到有两种方法可以做到这一点。

绝对进口:

import A.A
import A.B.B

或具有明确的相对导入,如在Python 2.5中使用PEP 328引入的:

# explicit relative
from .. import A
from . import B

什么是最pythonic的方式做到这一点?


“显式相对”示例是语法错误。相对进口必须在形式from _ import ...,所以你的例子是from .. import Afrom . import B
MestreLion

@MestreLion很好,您绝对正确!我将问题从更新import ..Afrom .. import A。值得注意的是,仅花了9年时间才有人注意到;)
Daniel Hepper

Answers:


52

绝对进口。从PEP 8:

强烈建议不要将相对进口用于包装内进口。始终对所有导入使用绝对包路径。即使现在PEP 328 [7]已在Python 2.5中完全实现,仍不鼓励使用其显式相对导入的样式。绝对导入更具可移植性,通常更具可读性。

显式相对导入是一种不错的语言功能(我想),但是它们不像绝对导入那样显式。更具可读性的形式是:

import A.A
import A.B.B

特别是如果您导入几个不同的名称空间。如果您看一些写得很好的项目/教程,其中包括从包中导入的内容,则它们通常遵循这种风格。

您需要进行一些更明确的额外击键操作,这将在将来其他人(也许您)试图找出您的名称空间(尤其是如果您迁移到3.x,其中包含某些软件包)时为他们节省了大量时间。名称已更改)。


@Rafe,“看看一些写得很好的项目……”有什么建议吗?
丹尼斯

@Denis:Rietveld是Guido van Rossum自己的项目,所以我认为这是个不错的地方(code.google.com/p/rietveld)。Python标准库不是很好,很多代码没有遵循约定。
拉菲·凯特勒

68
@Rafe:根据Guido所说,PEP-8的那部分已经过时了。mail.python.org/pipermail/python-dev/2010-October/104476.html
布兰登·罗德斯

12
现在,PEP-8中不再存在该声明。现在它声明了绝对进口,但相对进口是可以接受的替代方案。
dano 2014年

6
我的绝对导入问题是在另一个软件包中使用一个软件包时。就我而言,它作为git子模块存在。在这种情况下,尽管我可以导入顶层软件包,但该软件包以下的任何软件包都无法导入,因为它们无法找到带有绝对导入的自己的模块。而如果我在此底层使用相对导入,则一切正常。
davidA

122

不再强烈建议不要使用Python相对导入,但在这种情况下,强烈建议使用absolute_import。

请参见Guido本人的讨论

“这主要不是历史性的吗?在实施新的相对导入语法之前,相对导入存在各种问题。短期解决方案是建议不要使用它们。长期解决方案是实施明确的语法。现在现在是撤消反建议的时候了。当然,不用太过费心-我仍然发现他们有后天的品味;但是他们有他们的位置。”

OP正确链接了PEP 328,内容为:

提出了几个用例,其中最重要的是能够重新排列大型程序包的结构而无需编辑子程序包。另外,如果没有相对导入,包中的模块就无法轻松导入自身。

另请参阅几乎重复的问题:何时或为何在Python中使用相对导入

当然,它仍然是一个品味问题。尽管通过相对导入来移动代码更容易,但这也可能会意外地使事情中断。重命名进口商品并不难。

要从PEP 328强制执行新行为,请使用:

from __future__ import absolute_import

在这种情况下,隐式相对导入将不再可能(例如,import localfile将不再起作用from . import localfile)。为了使行为更干净,更可靠,建议使用absolute_import。

一个重要的警告是,由于 PEP 338PEP 366,相对导入要求将python文件作为模块导入-您无法执行具有相对导入的file.py,否则将得到一个ValueError: Attempted relative import in non-package

在评估最佳方法时应考虑到这一限制。在任何情况下,Guido都反对从模块运行脚本:

我在__main__机器上的任何其他提议中都为-1。唯一的用例似乎是正在运行的脚本,它们恰好位于模块目录中,我一直将其视为反模式。为了让我改变主意,您必须说服我不要。

关于此问题的详尽讨论可以在SO上找到;回覆。Python 3相当全面:


9
Guido在2010年写道,它仍在PEP中吗?如果PEP已过时,我们如何信任它们?
贾巴2014年

2
在可以修改的意义上,PEP就像美国的修正案。也有很多被拒绝的PEPS。PEP是建议。它们可以被接受,拒绝或过时,这通常意味着新的PEP。PEP 8是样式指南,因此可以在适当位置进行修改。
CppLearner 2014年

2
我对“包中的模块无法轻易导入自身...”部分感到困惑。我以前从未听说过如何导入模块。
matiascelasco 2014年

2
一个可能的例子@matiascelasco:如果您有foo / bar.py和foo / baz.py,但在其他地方也有baz.py。如果要从bar导入foo.baz,则可能需要确定要导入的内容,例如。import .baz-尽管这只是PEP中描述的许多类似情况的一种简化形式。
斯特凡诺

您的答案并未明确区分允许更改的范围。绝对不应该使用隐式相对导入,但是可以使用显式相对导入。隐式亲戚已从Python3中删除。
ninMonkey

33

相对导入不仅使您可以在以后不更改数十个内部导入的情况下自由重命名程序包,而且我在解决涉及循环导入或名称空间程序包之类的某些问题方面也取得了成功,因为它们不会将Python发送回“顶部”以从顶级名称空间重新开始搜索下一个模块。


4
根据Python样式指南,这是不鼓励使用的样式。它们严重影响了可读性,因此不值得您提及所带来的“便利”。如果您需要使用相对导入来解决问题,那么您做错了。
拉菲·凯特勒

14
请注意他的(Brandon Rhodes)对另一个答案的评论,并带有一个链接,表明不再鼓励这样做。
乔恩·库姆斯

1
@RafeKettler您能解释一下如何在一个本身包含在另一个软件包中的软件包中使用绝对导入吗?绝对导入将在内包中失败,因为它们不知道新的顶层。相对进口仍在继续。可能有人会争辩说,一开始不应该将程序包嵌套在另一个程序包中,但是某些代码是可重用的,并且这种情况经常发生。大量重用的代码未打包为公众使用,因此没有作为单独的软件包提供,因此最终使用了临时方法,例如VCS导入/子模块
davidA

3
@meowsqueak我同意,有些软件包不容易安装(它们不在pip上,您不想使用python setup.py installpython setup.py develop出于任何原因),在这些情况下,我会分叉源代码并将其添加为git子模块。当这些软件包在其自己的软件包名称上使用绝对导入时,它们的导入将失败。唯一的解决方案是使用显式相对导入。我认为应该鼓励这一点。
CMCDragonkai '18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.