Python中的相对导入有什么问题?


89

我最近升级了流行的Python样式检查器pylint的版本。

它贯穿了我的所有代码,指出了在同一软件包中导入模块的位置,而没有指定完整的软件包路径。

新的错误消息是W0403。

W0403:相对导入%r,应为%r

当检测到相对于软件包目录的导入时使用。


例如,如果我的软件包的结构如下:

/cake
  /__init__.py
  /icing.py
  /sponge.py
/drink

然后在海绵包装中写下:

import icing

代替

import cake.icing

我会收到此错误。


虽然我知道并非所有的Pylint消息都具有同等重要的地位,并且我不害怕忽略它们,但我不理解为什么这种做法被认为是一个糟糕的主意。

我希望有人可以解释这些陷阱,因此我可以改善自己的编码风格,而不是(按照我目前的计划)关闭此表面上虚假的警告。

Answers:


97

问题import icing在于您不知道它是绝对导入还是相对导入。icing可以是python路径中的模块,也可以是当前模块中的软件包。当本地包与python标准库包同名时,这很烦人。

您可以完全from __future__ import absolute_import关闭隐式相对导入。在PEP 328中对此进行了描述,包括有关歧义的理由。我相信Python 3000已完全关闭了隐式相对导入。

您仍然可以进行相对导入,但必须显式地进行它们,如下所示:

from . import icing

2
+1,特别是针对折衷解决方案,这可能是我应该采取的方式。
2012年

2
请注意,您也可以import .icing代替from . import icing
杰克

11
@Jack实际上我认为你不能。从PEP328的这部分开始:必须始终使用相对进口from <> import; import <>永远是绝对的。当然,可以from <> import通过省略前导点来使用绝对导入。其原因import .foo被禁止是因为后 import XXX.YYY.ZZZXXX.YYY.ZZZ是在表达式中使用。但是 .moduleY在表达式中不可用。
A.Wan 2015年

48

有几个很好的理由:

  1. 在移动模块时,相对导入很容易中断。

    假设您的包装中有一个foo.bar,一个foo.baz和一个baz模块。foo.barimport foo.baz,但使用相对导入。

    现在,如果你要移动foo.barbar,你的模块突然被导入不同baz

  2. 相对进口是模棱两可的。即使bar在上面的示例中没有遍历模块,也可以原谅新来的开发人员,因为他们没有意识到这baz实际上foo.baz不是根目录baz包。

    绝对导入使使用的模块明确。而作为import this鼓吹,明确优于隐式。

  3. Python 3完全禁用了隐式相对导入。现在,导入始终被解释为绝对import baz导入,这意味着在上面的示例中,始终导入顶级模块。您将必须使用显式导入语法(from . import baz)。

    因此,将示例从Python 2移植到3会导致意外的问题,现在使用绝对导入将使您的代码永不过时。


10
为#2和#3 +1。但是#1必须与整个目录移动(例如,下移某个级别)时发生的情况相对应。
2012年
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.