问题:为什么“导入*”不好?
建议不要import *
在Python中使用。
任何人都可以分享原因,以便下次可以避免吗?
回答 0
因为它在命名空间中放入了很多东西(可能会遮盖以前导入的其他对象,所以您将一无所知)。
因为您不完全知道要导入的内容,而且不容易找到从哪个模块导入的内容(可读性)。
因为您不能使用像
pyflakes
静态检测代码中的错误之类的出色工具。
回答 1
回答 2
您不传递**locals()
给函数,是吗?
因为Python缺少“包括”语句,并且该self
参数是明确的,而且范围规则相当简单,它通常很容易在一个变量指向一个手指,告诉哪里该对象来自-没有阅读其他模块,无任何IDE(由于语言是非常动态的,因此反省自省的方式)。
该import *
休息了这一切。
而且,它有隐藏错误的具体可能性。
import os, sys, foo, sqlalchemy, mystuff
from bar import *
现在,如果bar模块具有“ os
”,“ mystuff
”等属性中的任何一个,它们将覆盖显式导入的属性,并可能指向非常不同的事物。__all__
在bar中定义通常是很明智的-这说明了要隐式导入的内容-但是,如果不读取和解析bar模块并跟随其导入,仍然很难跟踪对象的来源。import *
获得项目所有权时,首先要解决的网络问题。
不要误会我:如果import *
丢失了,我会哭着拥有它。但是必须谨慎使用。一个好的用例是在另一个模块上提供Facade接口。同样,使用条件导入语句或在函数/类命名空间中进行导入也需要一些纪律。
我认为在大中型项目或具有多个贡献者的小型项目中,就静态分析而言,至少需要保持卫生(至少运行pyflakes甚至更好地配置正确的pylint)才能捕获多种错误。他们发生了。
当然,由于这是python-可以随意打破规则并进行探索-但要警惕可能增长十倍的项目,如果源代码缺少规范,那将是一个问题。
回答 3
可以from ... import *
在交互式会话中进行。
回答 4
那是因为您正在污染命名空间。您将在自己的命名空间中导入所有函数和类,这可能与您自己定义的函数冲突。
此外,我认为在维护任务中使用限定名称更为明确;您会在代码行本身上看到函数的来源,因此可以更轻松地签出文档。
在模块foo中:
def myFunc():
print 1
在您的代码中:
from foo import *
def doThis():
myFunc() # Which myFunc is called?
def myFunc():
print 2
回答 5
http://docs.python.org/tutorial/modules.html
请注意,通常不赞成
*
从模块或包进行导入的做法,因为这通常会导致可读性差的代码。
回答 6
假设您在名为foo的模块中具有以下代码:
import ElementTree as etree
然后在您自己的模块中,您可以:
from lxml import etree
from foo import *
现在,您有了一个难以调试的模块,看起来其中包含lxml的etree,但实际上是ElementTree。
回答 7
这些都是很好的答案。我要补充一点,当教新人们使用Python进行编码时,处理import *
非常困难。即使您或他们没有编写代码,它仍然是绊脚石。
我教孩子们(大约8岁)用Python编程来操纵Minecraft。我喜欢给他们一个有用的编码环境,以供他们使用(Atom Editor)并教授REPL驱动的开发(通过bpython)。在Atom中,我发现提示/完成与bpython一样有效。幸运的是,与其他一些统计分析工具不同,Atom并不受它的欺骗import *
。
但是,让我们举个例子…在这个包装器中,他们from local_module import *
是一堆模块,其中包括这个块列表。让我们忽略命名空间冲突的风险。通过这样做,您from mcpi.block import *
就可以使晦涩难懂的块的整个列表成为必需的东西,以便您了解可用的块。如果他们改用from mcpi import block
,则可以键入walls = block.
,然后会弹出一个自动完成列表。
回答 8
了解了人们在这里提出的有效观点。但是,我确实有一个论点,有时“星号导入”可能并不总是一个坏习惯:
- 当我想以所有常量都进入名为的模块的方式构造代码时
const.py
:- 如果我这样做
import const
,那么对于每个常量,我都必须将其称为const.SOMETHING
,这可能不是最方便的方法。 - 如果我这样做了
from const import SOMETHING_A, SOMETHING_B ...
,那么显然它太冗长而无法达到结构化的目的。 - 因此,我觉得在这种情况下,执行a
from const import *
可能是更好的选择。
- 如果我这样做
回答 9
这是非常糟糕的做法,原因有两个:
- 代码可读性
- 覆盖变量/功能等的风险
对于第1点:让我们看一个例子:
from module1 import *
from module2 import *
from module3 import *
a = b + c - d
在这里,看到代码,没有人会得到关于从哪个模块的想法b
,c
并且d
实际上属于。
另一方面,如果您这样做,则:
# 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
变量as设置为b
。当我做:
from module1 import *
from module2 import *
print b # will print the value from module2
此处的价值module1
丢失。很难调试为什么即使b
声明了module1
并且我已经编写了期望我的代码使用的代码也无法正常工作的原因module1.b
如果不同模块中的变量相同,并且不想导入整个模块,则可以执行以下操作:
from module1 import b as mod1b
from module2 import b as mod2b
回答 10
作为测试,我创建了一个模块test.py,其中包含2个函数A和B,分别打印“ A 1”和“ B 1”。使用以下命令导入test.py之后:
import test
。。。我可以将两个函数分别作为test.A()和test.B()运行,并且“ test” 在命名空间中显示为模块,因此,如果我编辑test.py,可以使用以下命令重新加载它:
import importlib
importlib.reload(test)
但是,如果我执行以下操作:
from test import *
在命名空间中没有对“测试”的引用,因此在编辑后(据我所知),没有办法重新加载它,这在交互式会话中是一个问题。而以下任何一项:
import test
import test as tt
将在命名空间中分别添加“ test”或“ tt”作为模块名称,这将允许重新加载。
如果我做:
from test import *
名称“ A”和“ B”作为功能出现在命名空间中。如果我编辑test.py,并重复以上命令,则不会重新加载功能的修改版本。
并且以下命令引发错误消息。
importlib.reload(test) # Error - name 'test' is not defined
如果有人知道如何重新加载加载有“ from module import *”的模块,请发布。否则,这是避免使用该表格的另一个原因:
from module import *
回答 11
如文档中所建议,您(几乎)永远不要import *
在生产代码中使用。
虽然*
从模块中导入很不好,但是从包中导入*更糟。默认情况下,from package import *
导入包的定义的任何名称__init__.py
,包括先前import
语句加载的包的任何子模块。
但是,如果包的__init__.py
代码定义了名为的列表__all__
,则将其视为from package import *
遇到时应导入的子模块名称的列表。
考虑以下示例(假设在中__all__
未定义sound/effects/__init__.py
):
# anywhere in the code before import *
import sound.effects.echo
import sound.effects.surround
# in your module
from sound.effects import *
最后一条语句会将echo
和surround
模块导入当前的命名空间(可能会覆盖先前的定义),因为它们是在执行语句sound.effects
时在包中定义的import
。