为什么“导入*”不好?

问题:为什么“导入*”不好?

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

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

It is recommended to not to use import * in Python.

Can anyone please share the reason for that, so that I can avoid it doing next time?


回答 0

  • 因为它在命名空间中放入了很多东西(可能会遮盖以前导入的其他对象,所以您将一无所知)。

  • 因为您不完全知道要导入的内容,而且不容易找到从哪个模块导入的内容(可读性)。

  • 因为您不能使用像pyflakes静态检测代码中的错误之类的出色工具。

  • Because it puts a lot of stuff into your namespace (might shadow some other object from previous import and you won’t know about it).

  • Because you don’t know exactly what is imported and can’t easily find from which module a certain thing was imported (readability).

  • Because you can’t use cool tools like pyflakes to statically detect errors in your code.


回答 1

根据Python禅宗

显式胜于隐式。

…不能肯定地说吗?

According to the Zen of Python:

Explicit is better than implicit.

… can’t argue with that, surely?


回答 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-可以随意打破规则并进行探索-但要警惕可能增长十倍的项目,如果源代码缺少规范,那将是一个问题。

You don’t pass **locals() to functions, do you?

Since Python lacks an “include” statement, and the self parameter is explicit, and scoping rules are quite simple, it’s usually very easy to point a finger at a variable and tell where that object comes from — without reading other modules and without any kind of IDE (which are limited in the way of introspection anyway, by the fact the language is very dynamic).

The import * breaks all that.

Also, it has a concrete possibility of hiding bugs.

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

Now, if the bar module has any of the “os“, “mystuff“, etc… attributes, they will override the explicitly imported ones, and possibly point to very different things. Defining __all__ in bar is often wise — this states what will implicitly be imported – but still it’s hard to trace where objects come from, without reading and parsing the bar module and following its imports. A network of import * is the first thing I fix when I take ownership of a project.

Don’t misunderstand me: if the import * were missing, I would cry to have it. But it has to be used carefully. A good use case is to provide a facade interface over another module. Likewise, the use of conditional import statements, or imports inside function/class namespaces, requires a bit of discipline.

I think in medium-to-big projects, or small ones with several contributors, a minimum of hygiene is needed in terms of statical analysis — running at least pyflakes or even better a properly configured pylint — to catch several kind of bugs before they happen.

Of course since this is python — feel free to break rules, and to explore — but be wary of projects that could grow tenfold, if the source code is missing discipline it will be a problem.


回答 3

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

It is OK to do from ... import * in an interactive session.


回答 4

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

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

在模块foo中:

def myFunc():
    print 1

在您的代码中:

from foo import *

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

def myFunc():
    print 2

That is because you are polluting the namespace. You will import all the functions and classes in your own namespace, which may clash with the functions you define yourself.

Furthermore, I think using a qualified name is more clear for the maintenance task; you see on the code line itself where a function comes from, so you can check out the docs much more easily.

In module foo:

def myFunc():
    print 1

In your code:

from foo import *

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

def myFunc():
    print 2

回答 5

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

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

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.


回答 6

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

import ElementTree as etree

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

from lxml import etree
from foo import *

现在,您有了一个难以调试的模块,看起来其中包含lxml的etree,但实际上是ElementTree。

Say you have the following code in a module called foo:

import ElementTree as etree

and then in your own module you have:

from lxml import etree
from foo import *

You now have a difficult-to-debug module that looks like it has lxml’s etree in it, but really has ElementTree instead.


回答 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.,然后会弹出一个自动完成列表。

These are all good answers. I’m going to add that when teaching new people to code in Python, dealing with import * is very difficult. Even if you or they didn’t write the code, it’s still a stumbling block.

I teach children (about 8 years old) to program in Python to manipulate Minecraft. I like to give them a helpful coding environment to work with (Atom Editor) and teach REPL-driven development (via bpython). In Atom I find that the hints/completion works just as effectively as bpython. Luckily, unlike some other statistical analysis tools, Atom is not fooled by import *.

However, lets take this example… In this wrapper they from local_module import * a bunch modules including this list of blocks. Let’s ignore the risk of namespace collisions. By doing from mcpi.block import * they make this entire list of obscure types of blocks something that you have to go look at to know what is available. If they had instead used from mcpi import block, then you could type walls = block. and then an autocomplete list would pop up.


回答 8

了解了人们在这里提出的有效观点。但是,我确实有一个论点,有时“星号导入”可能并不总是一个坏习惯:

  • 当我想以所有常量都进入名为的模块的方式构造代码时const.py
    • 如果我这样做import const,那么对于每个常量,我都必须将其称为const.SOMETHING,这可能不是最方便的方法。
    • 如果我这样做了from const import SOMETHING_A, SOMETHING_B ...,那么显然它太冗长而无法达到结构化的目的。
    • 因此,我觉得在这种情况下,执行a from const import *可能是更好的选择。

Understood the valid points people put here. However, I do have one argument that, sometimes, “star import” may not always be a bad practice:

  • When I want to structure my code in such a way that all the constants go to a module called const.py:
    • If I do import const, then for every constant, I have to refer it as const.SOMETHING, which is probably not the most convenient way.
    • If I do from const import SOMETHING_A, SOMETHING_B ..., then obviously it’s way too verbose and defeats the purpose of the structuring.
    • Thus I feel in this case, doing a from const import * may be a better choice.

回答 9

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

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

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

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

a = b + c - d

在这里,看到代码,没有人会得到关于从哪个模块的想法bc并且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

It is a very BAD practice for two reasons:

  1. Code Readability
  2. Risk of overriding the variables/functions etc

For point 1: Let’s see an example of this:

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

a = b + c - d

Here, on seeing the code no one will get idea regarding from which module b, c and d actually belongs.

On the other way, if you do it like:

#                   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

It is much cleaner for you, and also the new person joining your team will have better idea.

For point 2: Let say both module1 and module2 have variable as b. When I do:

from module1 import *
from module2 import *

print b  # will print the value from module2

Here the value from module1 is lost. It will be hard to debug why the code is not working even if b is declared in module1 and I have written the code expecting my code to use module1.b

If you have same variables in different modules, and you do not want to import entire module, you may even do:

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 *

As a test, I created a module test.py with 2 functions A and B, which respectively print “A 1” and “B 1”. After importing test.py with:

import test

. . . I can run the 2 functions as test.A() and test.B(), and “test” shows up as a module in the namespace, so if I edit test.py I can reload it with:

import importlib
importlib.reload(test)

But if I do the following:

from test import *

there is no reference to “test” in the namespace, so there is no way to reload it after an edit (as far as I can tell), which is a problem in an interactive session. Whereas either of the following:

import test
import test as tt

will add “test” or “tt” (respectively) as module names in the namespace, which will allow re-loading.

If I do:

from test import *

the names “A” and “B” show up in the namespace as functions. If I edit test.py, and repeat the above command, the modified versions of the functions do not get reloaded.

And the following command elicits an error message.

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

If someone knows how to reload a module loaded with “from module import *”, please post. Otherwise, this would be another reason to avoid the form:

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 *

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

As suggested in the docs, you should (almost) never use import * in production code.

While importing * from a module is bad, importing * from a package is probably even worse.

By default, from package import * imports whatever names are defined by the package’s __init__.py, including any submodules of the package that were loaded by previous import statements.

If a package’s __init__.py code defines a list named __all__, it is taken to be the list of submodule names that should be imported when from package import * is encountered.

Now consider this example (assuming there’s no __all__ defined in 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 *

The last statement will import the echo and surround modules into the current namespace (possibly overriding previous definitions) because they are defined in the sound.effects package when the import statement is executed.