Python:为什么应该禁止“from <module> import *”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3571514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python: Why should 'from <module> import *' be prohibited?
提问by OTZ
If you happen to have
如果你碰巧有
from <module> import *
in the middle of your program (or module), you would get the warning:
在您的程序(或模块)中间,您会收到警告:
/tmp/foo:100: SyntaxWarning: import * only allowed at module level
I understand why import *is discouraged in general (namespace invisibility),
but there are many situations where it would prove convenient, especially where
code is not shared with anyone.
我理解为什么import *一般不鼓励(命名空间不可见),但有很多情况证明它很方便,尤其是在代码不与任何人共享的情况下。
So, can anyone explain precisely in detail why from <module> import *should
be prohibited in all possible cases?
那么,谁能详细解释一下为什么from <module> import *在所有可能的情况下都应该被禁止?
采纳答案by zwol
I believe by "in the middle of your program" you are talking about an import insidea function definition:
我相信“在你的程序的中间”你是在谈论一个导入内部函数定义:
def f():
from module import * # not allowed
This is not allowed because it would make optimizing the body of the function too hard. The Python implementation wants to know all of the names of function-local variables when it byte-compiles a function, so that it can optimize variable references into operations on the (CPython) virtual machine's operand stack, or at least to local variable-slot operations rather than lookups in outer namespaces. If you could dump the entire contents of a module into a function's local namespace, then the compiler would have to assume that anyname in the function might possibly refer to a module global, because the list of names brought in by from module import *is only known at runtime.
这是不允许的,因为它会使优化函数体变得太难。Python 实现希望在对函数进行字节编译时知道函数局部变量的所有名称,以便它可以将变量引用优化为 (CPython) 虚拟机的操作数堆栈上的操作,或者至少是局部变量槽操作而不是在外部命名空间中查找。如果您可以将模块的全部内容转储到函数的本地命名空间中,那么编译器将不得不假设函数中的任何名称都可能引用模块全局,因为引入的名称列表from module import *仅在运行时才知道.
Putting from module import *in betweentop-level declarations is poor style, but it's allowed:
放在顶级声明from module import *之间是一种糟糕的风格,但它是允许的:
def f():
...
from module import *
def g():
...
EDIT April 2013:While looking into something else, I discovered that this restriction was introduced in Python 2.1, as a consequence of the "Nested Scopes" feature(PEP 227). Quoting from the link:
2013 年 4 月编辑:在查看其他内容时,我发现此限制是在 Python 2.1 中引入的,这是“嵌套作用域”功能(PEP 227)的结果。从链接引用:
One side effect of the change is that the
from module import *andexecstatements have been made illegal inside a function scope under certain conditions. The Python reference manual has said all along thatfrom module import *is only legal at the top level of a module, but the CPython interpreter has never enforced this before. As part of the implementation of nested scopes, the compiler which turns Python source into bytecodes has to generate different code to access variables in a containing scope.from module import *andexecmake it impossible for the compiler to figure this out, because they add names to the local namespace that are unknowable at compile time. Therefore, if a function contains function definitions orlambdaexpressions with free variables, the compiler will flag this by raising aSyntaxErrorexception.
更改的一个副作用是在某些条件下,
from module import *andexec语句在函数作用域内是非法的。Python 参考手册一直说这from module import *仅在模块的顶层是合法的,但 CPython 解释器以前从未强制执行过。作为嵌套作用域实现的一部分,将 Python 源代码转换为字节码的编译器必须生成不同的代码来访问包含作用域中的变量。from module import *并exec使其无法编译器摸不着头脑,因为他们的名字添加到本地命名空间是在编译时不可知。因此,如果函数包含lambda具有自由变量的函数定义或表达式,编译器将通过引发SyntaxError异常来标记它。
This clarifies the Python 3.x vs 2.x behavior discussed in the comments. It is always contrary to the language specification, but CPython 2.1 through 2.7 only issue an error for from module import *within a function if it might affect the compiler's ability to know whether a variable binds locally or in a containing scope. In 3.x it has been promoted to an unconditional error.
这阐明了注释中讨论的 Python 3.x 与 2.x 行为。它总是与语言规范相反,但 CPython 2.1 到 2.7 仅from module import *在函数内发出错误,如果它可能影响编译器知道变量是在本地绑定还是在包含范围内绑定的能力。在 3.x 中,它已升级为无条件错误。
SON OF EDIT:... and apparently flashk pointed this out years ago in another answer, quoting the same paragraph of "What's New in Python 2.1" yet. Y'all go upvote that now.
编辑之子:...显然 flashk 几年前在另一个答案中指出了这一点,引用了“Python 2.1 中的新功能”的同一段落。你们现在都去投赞成票。
回答by flashk
The release notes for Python 2.1seem to explain why this limitation exists:
Python 2.1的发行说明似乎解释了为什么存在此限制:
One side effect of the change is that the from module import * and exec statements have been made illegal inside a function scope under certain conditions. The Python reference manual has said all along that from module import * is only legal at the top level of a module, but the CPython interpreter has never enforced this before. As part of the implementation of nested scopes, the compiler which turns Python source into bytecodes has to generate different code to access variables in a containing scope. from module import * and exec make it impossible for the compiler to figure this out, because they add names to the local namespace that are unknowable at compile time. Therefore, if a function contains function definitions or lambda expressions with free variables, the compiler will flag this by raising a SyntaxError exception.
更改的一个副作用是 from module import * 和 exec 语句在某些条件下在函数作用域内是非法的。Python 参考手册一直说 from module import * 仅在模块的顶层才合法,但 CPython 解释器以前从未强制执行过这一点。作为嵌套作用域实现的一部分,将 Python 源代码转换为字节码的编译器必须生成不同的代码来访问包含作用域中的变量。from module import * 和 exec 使编译器无法弄清楚这一点,因为它们向本地命名空间添加了在编译时不可知的名称。因此,如果函数包含带有自由变量的函数定义或 lambda 表达式,
回答by kindall
It's not prohibited at all. It works fine, but you get a warning because it's generally a bad idea (for reasons others have gone into). You can, if you like, suppress the warning; the warnings module is what you want for that.
它根本没有被禁止。它工作正常,但您会收到警告,因为这通常是一个坏主意(出于其他人已经考虑过的原因)。如果愿意,您可以取消警告;警告模块正是您想要的。
回答by Alex Martelli
At any lexical level, from amodule import *is a "seemed a good idea at the time" design decision that has proven a real disaster in real life, with the possibleexception of handy exploration at the interactive interpreter prompt (even then, I'm not too hot on it -- import module as mforces only two extra characters to use qualified names instead [[just an m.prefix]], andqualified names are always sharper and more flexible than barenames, not to mention the great usefulness in exploratory interactive situations of having mavailable for help(m), reload(m), and the like!).
在任何词汇层面,from amodule import *是“在当时似乎是一个好主意”已经证明一个真正的灾难在现实生活中的设计决策,与可能在交互式解释提示符(得心应手探索例外,甚至然后,我不是太热在它上面 -import module as m只强制两个额外的字符使用限定名而不是 [[只是一个m.前缀]],并且限定名总是比裸名更清晰和更灵活,更不用说在探索性交互情况下具有m可用于help(m),的巨大用处reload(m),之类的!)。
This bedraggled construct makes it very hard, for the poor person reading the code (often in a doomed attempt to help debug it) to understand where mysteriously-appearing names are coming from -- impossible, if the construct is used more than once on a lexical level; but even when used just once, it forces laborious re-reading of the whole module every time before one can convince oneself that, yep, that bedraggled barename must come from the module.
这种杂乱无章的构造使得阅读代码的可怜人(通常是为了帮助调试它而注定失败)很难理解神秘出现的名称来自哪里 - 如果构造在一个系统上多次使用,这是不可能的词汇层面;但即使只使用一次,每次都需要费力地重新阅读整个模块,然后才能说服自己,是的,那个乱七八糟的裸名一定来自模块。
Plus, module authors usually don't go to the extreme trouble needed to "support" the horrid construct in question. If somewhere in your code you have, say, a use of sys.argv(and an import sysat the very top of your module, of course), how do you knowthat sysis the module it should be... or some completely different one (or a non-module) coming from the ... import *?! Multiply that by all the qualified names you're using, and misery is the only end result -- that, and mysterious bugs requiring long, laborious debugging (usually with the reluctant help of somebody who does"get" Python...!-).
另外,模块作者通常不会去“支持”所讨论的可怕构造所需的极端麻烦。如果某个地方你的代码中有,比方说,一个使用的sys.argv(和import sys你的模块的最顶部,当然),你怎么知道那sys是模块应该...或者一些完全不同的一个(或一非模块)来自... import *?! 乘上所有合格的名字,你正在使用,并且痛苦是唯一的最终结果-这一点,神秘的错误,需要长期,艰苦的调试(通常与别人的不情愿帮助谁做“获得”巨蟒...! - )。
Within a function, a way to add and override arbitrary local names would be even worse. As an elementary but crucial optimization, the Python compiler looks around the function's body for any assignment or other binding statements on each barename, and deems "local" those names it sees thus assigned (the others must be globals or built-ins). With an import *(just like with an exec somestringwithout explicit dicts to use as namespaces), suddenly it becomes a total mystery which names are local, which names are global -- so the poor compiler would have to resort to the slowest possible strategy for each name lookup, using a dict for local variables (instead of the compact "vector" it normally uses) and performing up to three dict look-ups for each barename referenced, over and over.
在 function 中,添加和覆盖任意本地名称的方法会更糟。作为一个基本但至关重要的优化,Python 编译器会在函数体中查找每个裸名上的任何赋值或其他绑定语句,并将它看到的那些名称视为“本地”,因此赋值(其他名称必须是全局变量或内置函数)。使用 an import *(就像使用exec somestring没有显式字典用作名称空间的 dict 一样),突然之间,哪些名称是本地名称,哪些名称是全局名称变得完全不解——因此,糟糕的编译器将不得不为每个名称查找采用最慢的策略,对局部变量使用 dict(而不是它通常使用的紧凑“向量”),并为每个引用的裸名一遍又一遍地执行最多三个 dict 查找。
Go to any Python interactive prompt. Type import this. What do you see? The Zen of Python. What's the last and probably greatest bit of wisdom in that text...?
转到任何 Python 交互式提示。键入import this。你看到了什么?Python 之禅。那篇文章中最后一点也是最大的智慧是什么......?
Namespaces are one honking great idea -- let's do more of those!
命名空间是一个很棒的想法——让我们做更多的事情!
By forcing the use of barenames where qualified names are sovastly preferable, you're essentially doing the very oppositeof this wise recommendation: instead of admiring the greatness and honkingtude of namespaces, and doing more of those, you're breaking downtwo perfectly good and ready-to-use namespaces (that of the module you're importing, and that of the lexical scope you're importing it in) to make a single, unholy, buggy, slow, rigid, unusable mess.
通过强制使用barenames其中合格的名称是如此远远优于,你基本上做的非常相反这个明智的建议:与其羡慕的命名空间的伟大和honkingtude,做更多的这些,你打破2完美好的和随时可用的名称空间(您正在导入的模块的名称空间,以及您正在导入它的词法范围的名称空间),以制造一个单一的、邪恶的、错误的、缓慢的、僵化的、无法使用的混乱。
If I could go back and change oneearly design decision in Python (it's a hard choice, because the use of defand especially lambdafor what Javascript so much more readably calls functionis a close second;-), I would retroactively wipe out the import *idea from Guido's mind. No amount of allegedconvenience for exploration at the interactive prompt can balance the amount of evil it's wrought...!-)
如果我可以回过头来更改Python 中的一个早期设计决策(这是一个艰难的选择,因为使用,def尤其是lambda对于 Javascript 更易读的调用function是紧随其后的;-),我会追溯地import *从 Guido 的头脑。在交互式提示中任何所谓的探索便利都无法平衡它所造成的邪恶数量......!-)
回答by Rick
others have given in-depth answers, I'll give a short overview answer of my understanding.. when using from you are making it so you can directly call any function in that module you imported without doing modulename.functioname (you can just call "functionname") this creates problems if you have 2 functions of the same name in different modules and also can create confusion when dealing with a lot of functions as you don't know what object/module it belongs to (from point of view of someone looking over already written code that isn't familiar with it)
其他人已经给出了深入的答案,我将给出我理解的简短概述答案..当你使用 from 你正在制作它时,你可以直接调用你导入的模块中的任何函数,而无需执行 modulename.functioname (你可以调用"functionname") 如果您在不同的模块中有两个同名的函数,这会产生问题,并且在处理许多函数时也会造成混淆,因为您不知道它属于哪个对象/模块(从角度来看)有人正在查看不熟悉它的已编写代码)
回答by e-satis
It's not prohibited, because...
这不是禁止的,因为...
... it's handy for quick scripts and shell exploring.
...它对于快速脚本和 shell 探索非常方便。
...but you should not keep it in any serious code
...但你不应该把它保存在任何严肃的代码中
- it can lead in importing names you don't know about and erase local names
- you can't know what's in use in your code, it's hard to know a script dependencies
- code completions won't work correctly anymore
- IDE convenient checks like "this var has not been declared" can't work anymore
- it make easier to create circular imports
- 它可能会导致导入您不知道的名称并删除本地名称
- 您无法知道代码中使用了什么,很难知道脚本依赖项
- 代码完成将不再正常工作
- 诸如“此变量尚未声明”之类的 IDE 方便检查不再起作用
- 更容易创建循环导入

