180

建议不要import *在 Python 中使用。

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

4

12 回答 12

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

  • 因为您不确切知道导入了什么,并且无法轻松找到从哪个模块导入了某个东西(可读性)。

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

于 2010-03-05T12:43:42.457 回答
59

根据Python 之禅

显式优于隐式。

……当然不能反驳?

于 2010-03-05T13:17:04.870 回答
42

你不传递**locals()给函数,是吗?

由于 Python 缺少“include”语句,并且self参数是显式的,并且范围规则非常简单,因此通常很容易将手指指向一个变量并判断该对象来自何处——无需读取其他模块,也无需任何类型IDE(无论如何,它在自省的方式上受到限制,事实上该语言是非常动态的)。

打破了这import *一切。

此外,它具有隐藏错误的具体可能性。

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

现在,如果 bar 模块具有任何“ os”、“ mystuff”等属性,它们将覆盖显式导入的属性,并可能指向非常不同的东西。在 bar 中定义通常是明智的——这说明了将隐式导入的内容——但如果不读取和解析 bar 模块并遵循__all__导入,仍然很难追踪对象的来源。当我获得一个项目的所有权时,网络是我首先要解决的问题。import *

不要误会我:如果import *丢失了,我会哭着得到它。但必须小心使用。一个好的用例是在另一个模块上提供外观接口。同样,使用条件导入语句或函数/类名称空间中的导入也需要一些纪律。

我认为在大中型项目或有多个贡献者的小型项目中,在静态分析方面需要最低限度的卫生——至少运行 pyflakes 甚至更好地配置正确配置的 pylint——以在之前捕获几种错误他们发生了。

当然,既然这是 python——随意打破规则,去探索——但要警惕可能增长十倍的项目,如果源代码缺少纪律,那将是一个问题。

于 2010-03-16T12:59:33.310 回答
21

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

此外,我认为使用限定名称对维护任务更清楚;您可以在代码行本身上看到函数的来源,因此您可以更轻松地查看文档。

在模块 foo 中:

def myFunc():
    print 1

在您的代码中:

from foo import *

def doThis():
    myFunc() # Which myFunc is called?

def myFunc():
    print 2
于 2010-03-05T12:45:55.563 回答
19

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

于 2010-03-05T13:14:16.377 回答
11

假设您在名为 foo 的模块中有以下代码:

import ElementTree as etree

然后在您自己的模块中,您有:

from lxml import etree
from foo import *

你现在有一个难以调试的模块,看起来它里面有 lxml 的 etree,但实际上有 ElementTree。

于 2010-03-05T13:18:20.343 回答
11

理解人们在这里提出的有效观点。但是,我确实有一个论点,有时“明星导入”可能并不总是一种不好的做法:

  • 当我想以所有常量都转到一个名为的模块的方式构造我的代码时const.py
    • 如果我这样做import const,那么对于每个常量,我必须将其称为const.SOMETHING,这可能不是最方便的方式。
    • 如果我这样做from const import SOMETHING_A, SOMETHING_B ...,那么显然它太冗长并且违背了结构化的目的。
    • 因此,我觉得在这种情况下,做 afrom const import *可能是一个更好的选择。
于 2016-12-26T08:57:57.493 回答
10

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

请注意,通常不赞成*从模块或包导入的做法,因为它通常会导致代码可读性差

于 2010-03-05T12:45:31.337 回答
9

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

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

但是,让我们举这个例子......在这个包装器中,它们from local_module import *是一堆模块,包括这个块列表。让我们忽略命名空间冲突的风险。通过这样做from mcpi.block import *,他们使整个晦涩类型的块列表成为您必须查看才能知道可用的东西。如果他们改为使用from mcpi import block,那么您可以键入walls = block.,然后会弹出一个自动完成列表。 Atom.io 截图

于 2015-12-27T07:38:22.220 回答
6

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

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

对于第 1 点:让我们看一个例子:

from module1 import *
from module2 import *
from module3 import *

a = b + c - d

在这里,在看到代码时,没有人会知道来自哪个模块b,实际上属于哪个模块。cd

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

#                   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
于 2016-11-09T23:05:58.297 回答
2

正如文档中所建议的,您应该(几乎)永远不要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 *

最后一条语句将echoandsurround模块导入当前命名空间(可能覆盖以前的定义),因为它们是在执行语句sound.effects时在包中定义的。import

于 2019-01-25T16:16:01.710 回答
2

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

import test

. . . 我可以将 2 个函数作为 test.A() 和 test.B() 运行,并且“test”在命名空间中显示为一个模块,所以如果我编辑 test.py,我可以重新加载它:

import importlib
importlib.reload(test)

但是,如果我执行以下操作:

from test import *

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

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 *
于 2017-05-03T01:41:34.520 回答