为什么“导入*”不好?

build议不要在Python中使用import *

任何人都可以请分享这个原因,这样我可以避免下一次做?

  • 因为它将很多东西放到你的名字空间中(可能会隐藏以前导入的其他对象,而你不知道它)。

  • 因为你不知道什么是导入,不能从哪个模块find某个东西容易导入(可读性)的地方。

  • 因为你不能使用像pyflakes这样的酷工具来检测代码中的静态错误。

根据Python禅 :

显式比隐式更好。

…不能与此争论,当然?

你不通过**locals()的function,是吗?

由于Python缺less一个“include”语句, 并且 self参数是显式的, 并且范围规则非常简单,所以通常很容易将一个手指指向一个variables并告诉该对象来自何处 – 而不需要读取其他模块IDE的种类(无论如何,这是内省的方式,语言是非常dynamic的)。

import *打破了这一切。

另外,它具有隐藏bug的具体可能性。

 import os, sys, foo, sqlalchemy, mystuff from bar import * 

现在,如果bar模块具有任何“ os ”,“ mystuff ”等属性,它们将覆盖显式导入的属性,并可能指向非常不同的东西。 在bar中定义__all__通常是明智的 – 这表明隐式地导入了什么 – 但是仍然很难追踪对象来自哪里,而不需要读取和parsingbar模块并在其后导入。 import *networkingimport *是我获得项目所有权的第一件事。

不要误解我:如果import *失踪了,我会哭的。 但必须谨慎使用。 一个很好的用例是通过另外一个模块提供一个Facade接口。 同样,使用条件导入语句,或者在函数/类名称空间内导入,需要一点训练。

我认为,在大中型项目中,或者与几个贡献者一起的小项目,在静态分析方面至less需要卫生 – 至less运行pyflakes,或者更好地configuration一个适当的pylint – 以便捕捉几种types的bug他们发生。

当然,因为这是python – 随意破坏规则,并探索 – 但要小心可能会增长十倍的项目,如果源代码缺less纪律,这将是一个问题。

那是因为你在污染命名空间。 你将在你自己的命名空间中导入所有的函数和类,这可能与你自己定义的函数冲突。

此外,我认为使用合格的名称对于维护任务更为明确; 你可以在代码行看到函数来自哪里,所以你可以更容易地查看文档。

在模块foo中:

 def myFunc(): print 1 

在你的代码中:

 from foo import * def doThis(): myFunc() # Which myFunc is called? def myFunc(): print 2 

在交互式会话中执行from ... import *可以。

http://docs.python.org/tutorial/modules.html

请注意,一般来说,从模块或包导入*的做法是不被接受的,因为它经常导致代码的可读性差

假设你在一个叫做foo的模块中有下面的代码:

 import ElementTree as etree 

然后在你自己的模块中有:

 from lxml import etree from foo import * 

你现在有一个难以debugging的模块, 看起来好像有lxml的etree,但是真的有ElementTree。

这些都是很好的答案。 我将补充一点,当教新人在Python中编写代码时,处理import *是非常困难的。 即使你或他们没有写代码,它仍然是一个绊脚石。

我教孩子们(大约8岁)用Python编程来操纵Minecraft。 我喜欢给他们一个有用的编码环境( Atom Editor ),并教导REPL驱动的开发(通过bpython )。 在Atom中,我发现提示/完成和bpython一样有效。 幸运的是,与其他一些统计分析工具不同,Atom不会被import *迷惑。

然而,让我们from local_module import *这个例子…在这个包装器中,他们from local_module import *包含这个块列表的一堆模块。 让我们忽略命名空间冲突的风险。 通过from mcpi.block import *做他们做这个模糊的types块的整个列表,你必须去看看什么是可用的东西。 如果他们使用from mcpi import block ,则可以键入walls = block. 然后会popup一个自动完成列表。 Atom.io截图

明白了人们放在这里的有效点。 但是我有一个论点,有时候,“明星import”可能并不总是一个坏习惯:

  • 当我想以这样的方式构build我的代码,所有的常量到一个名为const.py的模块:
    • 如果我import const ,那么对于每个常量,我必须把它称为const.SOMETHING ,这可能不是最方便的方法。
    • 如果我from const import SOMETHING_A, SOMETHING_B ... ,那么显然它太冗长了,并且破坏了结构化的目的。
    • 因此,我觉得在这种情况下, from const import *做一个可能是一个更好的select。

作为一个testing,我创build了一个带有2个函数A和B的模块test.py,分别打印“A 1”和“B 1”。 导入test.py后:

 import test 

。 。 。 我可以运行test.A()和test.B()和test.A()这两个函数作为模块在命名空间显示,所以如果我编辑test.py我可以重新加载它:

 import importlib importlib.reload(test) 

但是,如果我做到以下几点:

 from test import * 

在命名空间中没有引用“testing”,因此在编辑之后无法重新加载它(据我所知),这是交互式会话中的一个问题。 鉴于以下任一情况:

 import test import test as tt 

将在名称空间中添加“test”或“tt”(分别)作为模块名称,这将允许重新加载。

如果我做:

 from test import * 

名字“A”和“B”作为函数出现在名字空间中。 如果我编辑test.py,并重复上面的命令,函数的修改版本不会被重新加载。

以下命令引发错误消息。

 importlib.reload(test) # Error - name 'test' is not defined 

如果有人知道如何重新加载一个模块加载“从模块导入*”,请张贴。 否则,这将是避免这种forms的另一个原因:

 from module import * 

这是一个非常糟糕的做法,有两个原因:

  1. 代码可读性
  2. 覆盖variables/函数等的风险

对于第一 :我们来看一个例子:

 from module1 import * from module2 import * from module3 import * a = b + c - d 

在这里,在看代码的时候,没有人会从bcd实际属于哪个模块得到想法。

另一方面,如果你这样做:

 # vv will know that these are from module1 from module1 import b, c # way 1 import module2 # way 2 a = b + c - module2.d # ^ will know it is from module2 

这对你来说更加清洁,join你的团队的新人也会有更好的想法。

对于第二 :假设说module1module2variables都是b 。 当我这样做时:

 from module1 import * from module2 import * print b # will print the value from module2 

这里来自module1的值会丢失。 这将是很难debugging为什么代码不工作,即使bmodule1声明,我已经写了代码,期望我的代码使用module1.b

如果你在不同的模块中有相同的variables,并且你不想导入整个模块,你甚至可以这样做:

 from module1 import b as mod1b from module2 import b as mod2b