应该避免使用通配符导入吗?

69

我正在使用PyQt并遇到这个问题。如果我的导入语句如下:

from PyQt4.QtCore import *
from PyQt4.QtGui import *

然后pylint会给出成百上千个“Unused import”警告。我不敢轻易将它们关闭,因为可能有其他实际上有用的未使用的导入需要查看。另一个选项是这样做:

from PyQt4.QtCore import Qt, QPointF, QRectF
from PyQt4.QtGui import QGraphicsItem, QGraphicsScene, ...

最终我在QtGui行上拥有了9个类。还有第三种选择,即:

from PyQt4 import QtCore, QtGui

然后,每当我使用这些类时,都需要以QtCore或QtGui为前缀。

目前,我对我在项目中最终要采用哪种方式持中立态度,尽管从我的角度来看,最后一种方式似乎是最痛苦的。在这里有什么常见的做法?有没有技术原因来使用一种风格而不是另一种?


我收藏了这个问题,因为我想看答案,但我也很好奇为什么会这样做。通常我只导入我需要的东西,我知道我需要什么,所以我只导入那些东西。也许我太天真了,但在我看来,输入QtCore.something的“痛苦”似乎比浪费处理器时间导入数百个未使用的项目要好(自动填充?)。我知道这样做会让我在代码审查中受到抨击。他们会问我关于我使用的每个导入的问题。 - xnine
我同意对于专业代码来说这是个问题,但对于个人脚本或项目来说,这并不是一个大问题。特别是因为导入很可能会在程序启动时立即发生,所以它不应该影响运行性能,只会影响启动时间。 - Colin
相关内容:为什么“import *”是不好的? - Stevoisiak
6个回答

71
你问题标题的答案是“是”的:我建议永远不要使用from ... import *,我在另一个非常近期的答案中讨论了原因。简而言之,有限制的裸名很少使用,所以在你提出的选项中,“第三个选项”是最佳选择(因为你将使用有限定的名称,而不是裸名)。
(与有限制的裸名相比,有限定名称的优点包括易于模拟/模拟测试,减少或消除由意外重新绑定引起的未被注意到的错误的风险,能够“半伪造”跟踪类中的顶级名称,以便记录您正在使用的内容并简化诸如分析等活动,等等——缺点几乎没有... 参见Python禅宗中的最后一个重要教义,交互式解释器提示符下的import this
同样好的方法是,如果你不想写7个额外的字符来输入QtCore.whatever,那么可以缩写:from PyQt4 import QtCore as Crfrom PyQt4 import QtGui as Gu(然后使用Cr.blahGu.zorp等)。像所有缩写一样,这是简洁和清晰之间的一种风格权衡(你更喜欢把一个变量命名为count_of_all_widgets_in_the_inventorynum_widgets还是x?通常中间的选择最好,但不总是;-)。
顺便说一句,我不会在单个fromimport语句中使用多个as子句(可能会令人困惑),我宁愿有多个语句(如果任何导入出现问题,则更容易调试,在将来修改导入时也更易于编辑...)。

另一个合格的优点是,您无法像PyQt这样的大型库一样导入所有内容,然后意外地与您不知道存在的某些东西发生命名空间冲突。 - user106514
1
可能有一个打字错误,“import from this” -> “import this”。 - sunqiang
5
在我看来,这个答案对于一个特殊情况已经过时了:在“init.py”文件中使用通配符导入从定义了__all__的模块中导入是很好的。 - Neil G
1
@sunqiang:不,这不是打错了 —— 试一下就知道了。 - martineau

26

使用import *也有其好处。例如,Django开发人员通常会有许多配置文件,并使用import *将它们链接在一起:

settings.py:
FOO = 1
BAR = 2
DEBUG = False

test_settings.py:
from settings import *
DEBUG = True
在这种情况下,import * 的大多数缺点都变成了优点。

这些文件是一次性的,旨在被star导入。PyQt4.QtGui不符合要求!C-; - Phlip
13
同意,但这篇文章的标题是“应该避免使用通配符导入吗?”而不是“应该避免在PyQt4中使用通配符导入吗?” - Mark E. Haase
1
我认为这个答案需要展示好的场景,而不仅仅是挑选主要场景并说它不好。这就像是在问“我应该开车上路吗”,有人说“是的”,另一个人说“如果有‘禁止通行’标志就不要开”。 - James
我认为在处理常量时,from settings import * 是一种特别好的做法。它可以从主文件中移除杂乱的代码 - 尤其是在处理大型集合(如列表和字典)时尤为有益。 - DaveL17

3

Python文档说:

尽管某些模块被设计为只在使用import *时导出符合特定模式的名称,但在生产代码中仍被认为是不良实践。

它可能会产生副作用,并且很难调试。

个人而言,我使用import而不是from import,因为我发现在文件开头有很多糟糕的大声明,我认为这会使代码更易读。

import PyQt4

PyQt4.QtCore

如果模块名称太长,可以使用 as 关键字在本地重命名。例如:
import PyQt4.QtCore as Qc

如果你有一个鼠标事件处理程序,例如,你可能会有这样一行代码:"if event.buttons() & PyQt4.QtCore.Qt.LeftButton:"?那似乎不如"if event.buttons() & Qt.LeftButton:"易读。 - Colin
4
如果太长了,我会这样做:导入 PyQt4.QtCore.Qt 中的 Qc,然后使用 Qc.LeftButton。 - luc
我的意思是:import PyQt4.QtCore.Qt as Qc - luc

1

导入PyQt4是一个特殊情况。
有时我会选择“第一种选项”进行快速和简单的编码,并在代码变得越来越长时将其转换为“第二种选项”。
命名空间冲突可能在这里不是什么大问题,我还没有看到其他包以大写“Q”开头的名称。每当我完成一个PyQt4脚本时,就将“from PyQt4.QtGui import *”转换为类似于

from PyQt4.QtGui import (QApplication, QDialog, QLineEdit, QTextBrowser,
                         QVBoxLayout)

只是提供信息,多行导入使用括号 在这里很方便。


1
我使用“import *”导入我使用的PyQt模块,但我将它们放在自己的模块中,这样就不会污染用户的命名空间。例如:

在qt4.py中:

 from PyQt4.QtCore import *
 from PyQt4.QtGui import *

然后像这样使用:

 import qt4
 app = qt4.QApplication(...)

3
这是否相当于“import PyQt4.QtCore as qt4”?如果这样做,我想你需要为QtCore和QtGui使用单独的命名空间,但这似乎并不是什么坏事。 - Colin
如果在qt4.py中只有一个导入(import),那么它是等效的。在编程时,我并没有发现QtCore、QtGui等之间的区别非常有用。 - xioxox
这是一个很好的解决方案,可以避免源文件头部的混乱代码。Qt模块之间不会发生冲突,据我所知,这不会带来任何问题。 - mfitzp

0

在一般情况下,我非常反对使用import *。 但在PySide2的情况下,这是少数例外之一:

from PySide2 import *

PySide2的导入模式是导入所有已知模块的模式。这种导入非常方便,因为导入总是正确的。 该常量是从CMAKE生成器计算出来的。在交互式控制台中快速尝试某些内容以及自动化测试时非常有用。

对于高级用法,直接使用PySide2.__all__变量也是有意义的,它实现了此功能。 PySide2.__all__的元素按依赖关系排序,因此首先是QtCore,然后是QtGuiQtWidgets,...等等。


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