建议不要在python中使用import *。
有人能告诉我原因吗?这样我下次就可以避免了。
- 副本:stackoverflow.com/questions/2360724/…
- 这取决于您是在编写脚本还是在编写需要重用的代码。有时忽略代码标准是值得的。"如果您有一个明确的命名约定来说明事物的来源,那么import*"也可以。例如,"从cats导入*;tabbycat;maineconcat;calicocat;"
- 在python 2或3中,import *最初并不适合我。
因为它在您的名称空间中放置了很多东西(可能会隐藏以前导入的其他对象,而您不知道)。
因为您不知道确切导入了什么,也不容易找到从哪个模块导入了某个东西(可读性)。
因为您不能使用像pyflakes这样的酷工具静态地检测代码中的错误。
- +1因为你比我快,还添加了Pyflakes参数。本来应该是+2,但我不能这么说:)
- 是的,我真的很讨厌别人用*进口的工作,因为那样的话,我就不能只运行Pyflakes并快乐地工作,而是必须修理那些进口的产品。不过,很好,有了那片薄饼,我就可以:
- 作为一个具体的例子,numpy的许多用户在执行from numpy import *或"有用"工具时被numpy.any阴影any咬伤。
- 出于同样的原因,我应该避免为ipython使用--pylab开关吗?
- 为了强调我在阅读之前从未想到的一个风险("可能会掩盖以前导入的其他对象"):import *使import语句的顺序非常重要…即使对于通常不关心进口订单的标准库模块也是如此。当进口战争的前伤亡者成为唯一的幸存者时,一些像按字母顺序排列你的import语句这样无辜的东西可能会破坏你的脚本。(即使您的脚本现在可以工作,而且永远不会更改,但如果导入的模块引入一个新名称来替换您所依赖的名称,它可能稍后突然失败。)
根据《Python禅》:
Explicit is better than implicit.
…当然,不能反驳吗?
- 事实上,你可以反驳。这也是完全不一致的,因为您没有在Python中显式地声明变量,一旦您分配给它们,它们就会出现。
- 因为声明变量不是显式的,所以它是多余的,并且声明了它们的类型。这就是为什么C++将介绍EDOCX1,6,我是非常喜欢的。尽管这也是多余的:—)
- @Gruszczy:声明变量对什么来说是多余的?分配?不,这是两个独立的概念,声明某个东西可以传达一个非常独特和重要的信息。不管怎样,直言不讳总是与冗余有某种联系,它们是同一个硬币的两面。
- @康拉德·鲁道夫:多余的,因为没有赋值的声明是没有意义的(好的编译器也会对此发出警告)。另一方面,没有变量(某些声明隐式或显式)的赋值是不可能的。从此分离的概念是的,但密切相关。
- @克里斯说得对,但那不是我的观点。我的观点是,未能显式声明变量会导致错误。你说"没有[声明]的转让是不可能的"。但那是错误的,我的观点是,不幸的是,python使这一切成为可能。
- @康拉德·鲁道夫:你需要一些声明规则,明确的或隐含的,否则分配将毫无意义。python同样非常清楚的规则:第一个赋值=声明。声明行在没有赋值的情况下提供给编译器的唯一信息是变量的类型,而且由于python是无类型的,所以无论如何都不需要这样做。除此之外,声明中唯一的一点是避免错别字,但是现代的IDES很好地处理了这一点。那么为什么在源代码中使用无用的噪声呢?
- @克里斯声明提供给编译器的另一条信息是,您确实打算声明一个新的变量。对于类型系统来说,这是一个至关重要的信息。您认为现代的IDE解决了错误的输入问题,但这是完全错误的,事实上,这是非静态编译语言中的一个实质性问题,这就是Perl添加use strict(javascript var)的原因。顺便提一句,当然python不是无类型的(实际上它是强类型的)。不管怎样,即使你是对的,这仍然会与这个答案中引用的python的禅相矛盾。
- @KonradRudolph:好吧,python是动态类型的,变量名没有附加到任何给定的类型上。如果您习惯了一些非常糟糕的做法,那么声明一个新变量的意图就变成了一个真正的问题:对周围的一切重复使用相同的变量名。只有在多次(两次)分配给同一个变量时才会出现问题。考虑到python规则,如果在任何唯一的赋值中错误地输入变量名(不要与globals或成员混淆),就不会很难被咬到。Perl是非常不同的,因为变量在读取时是自动激活的,而在Python中则不是这样。
- @康拉德:鲁道夫和它并不是contradict"禅"的Python。你可以容易的知识是任何可变也declared单纯找它与你的优先股,文本编辑。它只是occurs,declaration of的可变定义的第一个分配到它或在appearence功能参数或进口。
- Kriss @你拥有它是错误的:reusing相同的名称是不可变的,同样的问题reusing可变(公元前相同的名称在相同的scope)。显式declarations到底这会预防错误(和其他人,基于简单的mistyping,这一点,我说,但是一个非常常见的问题consuming和时间-即使,虽然你是正确的,问题是更大的在Perl像languages)。和矛盾allude)到的禅的requirement为explicitness,这是bodily thrown出窗口的睾丸。
- @ Konrad鲁道夫:如果你执行两个consecutive assignments在Python中相同的功能,你会有一个名称和2个不同的变量的描述是因为Python的腹部的拷贝的semantic C写的。的名字是可变的,不过处理到一些对象underlying雅由一些constructor显式"的情况在类或建在为primitive类型。declaration of的可变的手段得到的空间,这也为可变的运行时间在操作上的Python performed在分配的时间。在Python的分配也派。因此它也不只是forbidden到忘了可变initialisation:它也不可能。
- Kriss @你继续到小姐的点。我从来没有talked关于forgetting initialisation。
- 让我们继续这discussion在聊天。
你没有把**locals()传递给函数,是吗?
由于python缺少一个"include"语句,并且self参数是显式的,并且作用域规则非常简单,所以通常很容易将手指指向一个变量,并告诉该对象来自何处——不读取其他模块,也不使用任何类型的IDE(不管怎样,这些都限制了自省的方式,因为事实上语言是非常动态的)。
import *打破了这一切。
此外,它还具有隐藏bug的具体可能性。
1 2
| import os, sys, foo, sqlalchemy, mystuff
from bar import * |
现在,如果BAR模块有"os"、"mystuff"等任何一个……属性,它们将覆盖显式导入的属性,并可能指向非常不同的内容。在BAR中定义__all__通常是明智的——这说明了将隐式导入的内容——但如果不读取和分析BAR模块并遵循其导入,仍然很难跟踪对象的来源。当我拥有一个项目的所有权时,我首先要修复的是import *的网络。
别误会我了:如果import *不见了,我会哭着要它。但必须小心使用。一个好的用例是在另一个模块上提供一个外观接口。同样,在函数/类名称空间中使用条件导入语句或导入也需要一些规则。
我认为在大中型项目中,或者有几个贡献者的小项目中,静态分析(至少运行pyflakes,或者更好的是正确配置的pylint)需要最低的卫生要求,以便在发生之前捕获几种错误。
当然,因为这是python——可以随意打破规则和探索——但是要小心可能增长十倍的项目,如果源代码缺少规则,这将是一个问题。
- 我喜欢你的态度。
- Python的2.x确实有一个"包括"声明。它的execfile()叫。luckily, rarely用和过去在3.x.
- 怎么**vars()包括globals如果叫功能也在另一个文件?P:
可以在交互式会话中执行from ... import *。
这是因为您正在污染名称空间。您将导入自己名称空间中的所有函数和类,这可能与您自己定义的函数冲突。
此外,我认为使用限定名对于维护任务来说更清楚;您可以在代码行本身看到函数的来源,这样您可以更容易地签出文档。
在模块Fo:
在您的代码中:
1 2 3 4 5 6 7
| from foo import *
def doThis():
myFunc() # Which myFunc is called?
def myFunc():
print 2 |
http://docs.python.org/tutorial/modules.html网站
Note that in general the practice of importing * from a module or package is frowned upon, since it often causes poorly readable code.
假设在名为foo的模块中有以下代码:
1
| import ElementTree as etree |
在你自己的模块中,你有:
1 2
| from lxml import etree
from foo import * |
您现在有一个很难调试的模块,看起来它包含lxml的etree,但实际上它包含elementtree。
这些都是很好的答案。我还要补充一点,在用Python教新人代码时,处理import *是非常困难的。即使你或他们没有写代码,这仍然是一个绊脚石。
我教孩子们(大约8岁)用Python编程来操纵雷艇。我喜欢为他们提供一个有用的编码环境来与(Atom编辑器)一起工作,并教授repl驱动的开发(通过bpython)。在Atom中,我发现提示/完成和bpython一样有效。幸运的是,与其他统计分析工具不同,Atom没有被import *愚弄。
然而,让我们举个例子……在这个包装器中,他们使用了一组模块,包括这个块列表。让我们忽略名称空间冲突的风险。通过执行from mcpi.block import *,他们会列出所有不清晰类型的块,您必须查看这些块才能知道可用的是什么。如果他们使用了from mcpi import block,那么您可以键入walls = block.,然后会弹出一个自动完成列表。
理解人们在这里提出的有效观点。然而,我确实有一个论点,即有时,"星导入"并不总是一种坏做法:
- 当我想要以这样一种方式构造我的代码时,所有的常量都会被放到一个名为const.py的模块中:
- 如果我做import const,那么对于每个常量,我必须将其称为const.SOMETHING,这可能不是最方便的方法。
- 如果我做from const import SOMETHING_A, SOMETHING_B ...,那么显然这太冗长了,并且破坏了结构化的目的。
- 因此,我觉得在这种情况下,做一个from const import *可能是一个更好的选择。
作为测试,我创建了一个模块test.py,它有两个功能a和b,分别打印"a 1"和"b 1"。导入test.py后使用:
. …我可以运行test.a()和test.b()这两个函数,"test"在命名空间中显示为一个模块,因此如果我编辑test.py,我可以用以下命令重新加载它:
1 2
| import importlib
importlib.reload(test) |
但如果我这样做:
命名空间中没有对"test"的引用,因此在编辑之后(据我所知)无法重新加载它,这在交互式会话中是一个问题。鉴于以下任一项:
1 2
| import test
import test as tt |
将在命名空间中添加"test"或"tt"(分别)作为模块名,这将允许重新加载。
如果我这样做:
名称"a"和"b"作为函数出现在命名空间中。如果我编辑test.py并重复上述命令,则不会重新加载修改后的函数版本。
下面的命令将引发一条错误消息。
1
| importlib.reload(test) # Error - name 'test' is not defined |
如果有人知道如何重新加载加载了"从模块导入*"的模块,请发布。否则,这将是另一个避免使用表单的原因:
这是一种非常糟糕的做法,原因有两个:
代码可读性
覆盖变量/函数等的风险
对于点1:我们来看一个例子:
1 2 3 4 5
| from module1 import *
from module2 import *
from module3 import *
a = b + c - d |
在这里,当看到代码时,没有人会知道b、c和d实际上属于哪个模块。
另一方面,如果你喜欢:
1 2 3 4 5 6
| # v v 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 |
它对你来说更干净,而且新加入你团队的人会有更好的想法。
对于第2点:假设module1和module2都有变量b。当我这样做的时候:
1 2 3 4
| from module1 import *
from module2 import *
print b # will print the value from module2 |
这里,module1的值丢失。即使在module1中声明了b并且我编写了希望我的代码使用module1.b的代码,也很难调试为什么代码不工作。
如果您在不同的模块中有相同的变量,并且不想导入整个模块,您甚至可以这样做:
1 2
| from module1 import b as mod1b
from module2 import b as mod2b |
如文档中建议的,在生产代码中不应使用import *。
虽然从模块导入*很糟糕,但从包导入*则更糟。基本上,from package import *导入由包的__init__.py定义的任何名称,但它还包括由以前的import语句加载的包的任何子模块。
考虑这个例子:
1 2 3 4 5 6
| # anywhere in the code before import *
import sound.effects.echo
import sound.effects.surround
# in your module
from sound.effects import * |
最后一条语句将把echo和surround模块导入当前命名空间(可能覆盖以前的定义),因为它们在执行import语句时在sound.effects包中定义。