应该避免通配符导入吗?

Posted

技术标签:

【中文标题】应该避免通配符导入吗?【英文标题】:Should wildcard import be avoided? 【发布时间】:2011-04-06 14:52:25 【问题描述】:

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

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

然后 pylint 会给出数百个“未使用的导入”警告。我很犹豫是否要关闭它们,因为可能还有其他未使用的导入实际上很有用。另一种选择是这样做:

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

我最终在 QtGui 线上有 9 个课程。还有第三种选择,即:

from PyQt4 import QtCore, QtGui

然后在我使用它们时为所有类添加 QtCore 或 QtGui 前缀。

在这一点上,我不知道我最终会在我的项目中做哪一个,尽管从我的角度来看,最后一个似乎是最痛苦的。这里的常见做法是什么?使用一种风格而不是另一种风格是否有技术原因?

【问题讨论】:

我为这个问题加星标是因为我想看到答案,但我也很好奇为什么有人会这样做。通常我只导入我需要的东西,我知道我需要什么,所以我只导入那些东西。也许我很天真,但在我看来,键入 QtCore.something 的“痛苦”会比浪费处理器时间导入数百个未使用的项目更好(自动填充?)。我知道这样做会让我在代码审查中大吃一惊。他们会询问我使用的每个导入。 我同意你的专业代码,但对于个人脚本或项目,这不是什么大问题。特别是因为导入可能会在程序启动时发生,所以它不应该影响运行性能,只会影响启动时间。 相关:Why is “import *” bad? 【参考方案1】:

您的问题标题的答案是“是”:我建议永远不要使用from ... import *,我在另一个最近的答案中讨论了原因。简而言之,限定名称​​很好,裸名称非常有限,因此“第三个选项”在您呈现的人中是最佳选择(因为您将使用限定名称,而不是裸名称)。

(合格名称 wrt 裸名称的优点包括易于伪造/模拟以用于测试目的,降低了因意外重新绑定引起的未注意到错误的风险,能够“半伪造”“跟踪类”中的***名称目的是准确记录您正在使用的内容并简化分析等活动 - 缺点,几乎没有......另请参阅 Python Zen 中最后但并非最不重要的公案,import this at交互式解释器提示)。

同样好,如果你不喜欢说QtCore.whatever 的7 个额外字符,那就是缩写--from PyQt4 import QtCore as Crfrom PyQt4 import QtGi as Gu(然后使用Cr.blahGu.zorp)等等。像所有缩写一样,它是简洁和清晰之间的风格权衡(您更愿意将变量命名为 count_of_all_widgets_in_the_inventorynum_widgets 还是 x?通常中间选择是最好的,但并非总是如此;-)。

顺便说一句,我不会在单个 fromimport 语句中使用多个 as 子句(可能会令人困惑),我宁愿有多个语句(如果有任何导入也更容易调试)问题,如果您将来更改导入,则进行编辑,...)。

【讨论】:

qualified 的另一个优点 - 你不能像 PyQt 这样在一个巨大的库中导入所有东西,然后不小心导致与你不知道的东西发生命名空间冲突。 可能有错别字,"import from this" -> "import this" 在我看来,这个答案对于一种特殊情况已经过时了:最好在“init.py”文件中使用通配符导入来从定义__all__的模块导入。 @sunqiang:不,这不是错字——试试看。【参考方案2】:

import * 也有很好的案例。 IE。 Django 开发人员拥有许多配置文件并使用 import * 链接它们是很常见的:

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

test_settings.py:
from settings import *
DEBUG = True

在这种情况下,import * 的大多数缺点都变成了优点。

【讨论】:

这样的文件是一击奇迹,旨在通过明星导入。 PyQt4.QtGui 不合格! C-; @Phlip 同意,但是这篇文章的标题是“应该避免通配符导入吗?”不是“在 PyQt4 中应该避免通配符导入吗?” 我认为这个答案需要展示好的场景,而不是仅仅选择主要场景并说它很糟糕。这就像说“我应该在路上开车吗”,有人说“是”,有人说“如果有‘禁止进入’标志就不行”。【参考方案3】:

Python doc 说:

尽管某些模块设计为仅导出后面的名称 使用 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:”那样可读 如果太长我会这样做:在 Qc 处导入 PyQt4.QtCore.Qt,然后在 Qc.LeftButton 处导入 我的意思是:导入 PyQt4.QtCore.Qt 作为 Qc【参考方案4】:

我对我使用的 PyQt 模块使用“import *”,但是我把它们放在自己的模块中,所以它不会污染用户的命名空间。例如

在 qt4.py 中:

从 PyQt4.QtCore 导入 * 从 PyQt4.QtGui 导入 *

那就这样用吧

导入qt4 应用程序 = qt4.QApplication(...)

【讨论】:

这不等同于“import PyQt4.QtCore as qt4”吗?我想如果你这样做的话,你需要为 QtCore 和 QtGui 单独命名空间,但这似乎不是一件坏事。 如果在 qt4.py 中只有一个导入,它是等价的。我没有发现 QtCore、QtGui 等之间的区别……在编程时非常有用。 这是一个很好的解决方案,可以绕过源文件顶部的垃圾。 Qt 模块不会相互冲突,所以据我所知,这不会带来任何问题。【参考方案5】:

PyQt4 的导入是一种特殊情况。 有时我会选择“第一个选项”进行快速而肮脏的编码,当代码越来越长时将其转换为“第二个选项”。 命名空间冲突在这里可能没什么大不了的,我还没有看到其他包的名称以大“Q”开头。每当我完成一个 PyQt4 脚本时。将“从 PyQt4.QtGui import *”转换为……像“

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

" 仅供参考,parentheses for multi-line import 在这里很方便。

【讨论】:

【参考方案6】:

在一般情况下,我绝对反对import *。 对于PySide2,有一种罕见的例外情况适用:

from PySide2 import *

是从PySide2 导入所有已知模块的模式。这 导入很方便,因为导入总是正确的。 该常数是从CMAKE 生成器计算出来的。非常有帮助 在交互式控制台中快速尝试某些东西时,也在自动化测试中。

对于高级用法,也有意义 直接使用PySide2.__all__ 变量,它实现了这个 特征。 PySide2.__all__ 的元素按依赖排序, 所以首先是QtCore,然后是QtGuiQtWidgets,......等等。

【讨论】:

以上是关于应该避免通配符导入吗?的主要内容,如果未能解决你的问题,请参考以下文章

消息中间件 - 如何避免使用通配符订阅重入?

加入时如何不使用通配符避免列名重复

避免mysql注入应该避免都有哪些特殊字符

自动将通配符导入重构为 IntelliJ 中的显式导入(用于 Scala/Java)

egrep匹配表达式与通配符

如何在 IntelliJ 中停止通配符 Java 包导入