Python:为什么应该“from”导入*被禁止?

发布于 2024-09-16 04:59:49 字数 360 浏览 7 评论 0原文

如果您碰巧

from <module> import *

在程序(或模块)中间,您会收到警告:

/tmp/foo:100: SyntaxWarning: import * only allowed at module level

我理解为什么一般不鼓励 import * (命名空间不可见性), 但在很多情况下它会被证明是方便的,特别是在 代码不与任何人共享。

那么,任何人都可以准确详细地解释为什么 from导入 * 应该 在所有可能的情况下都被禁止?

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.

So, can anyone explain precisely in detail why from <module> import * should
be prohibited in all possible cases?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

墨落画卷 2024-09-23 04:59:49

我相信“在程序中间”您正在谈论函数定义内的导入:

def f():
    from module import *    # not allowed

这是不允许的,因为它会使优化函数体变得太困难。 Python 实现希望在字节编译函数时知道函数局部变量的所有名称,以便它可以将变量引用优化为 (CPython) 虚拟机操作数堆栈上的操作,或者至少优化为局部变量槽操作而不是在外部名称空间中查找。如果您可以将模块的全部内容转储到函数的本地命名空间中,那么编译器将不得不假设函数中的任何名称都可能引用模块全局,因为名称列表带来了in by from module import * 仅在运行时才知道。

from module import * 放在顶级声明之间的方式很差,但这是允许的:

def f():
    ...

from module import *

def g():
    ...

编辑 2013 年 4 月: 在研究其他内容时,我发现这个限制是在 Python 2.1 中引入的,这是由于 “嵌套作用域”功能 (PEP 227)。引用自链接:

此更改的一个副作用是,在某些条件下,from module import *exec 语句在函数作用域内变得非法。 Python 参考手册一直说 from module import * 仅在模块的顶层合法,但 CPython 解释器以前从未强制执行过这一点。作为嵌套作用域实现的一部分,将 Python 源代码转换为字节码的编译器必须生成不同的代码来访问包含作用域中的变量。 from module import *exec 使编译器无法弄清楚这一点,因为它们向本地命名空间添加了编译时不可知的名称。因此,如果函数包含带有自由变量的函数定义或 lambda 表达式,编译器将通过引发 SyntaxError 异常来标记此情况。

这澄清了评论中讨论的 Python 3.x 与 2.x 行为。它始终与语言规范相悖,但 CPython 2.1 到 2.7 仅在函数内的 from module import * 可能影响编译器了解变量是在本地绑定还是在变量中绑定的能力时才会发出错误。包含范围。在 3.x 中,它已升级为无条件错误。

编辑之子: ...显然 flashk 几年前在另一个答案中指出了这一点,引用了“Python 2.1 中的新增功能”的同一段。你们现在就去投票吧。

I believe by "in the middle of your program" you are talking about an import inside a 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 any name 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.

Putting from module import * in between top-level declarations is poor style, but it's allowed:

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:

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.

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.

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.

情未る 2024-09-23 04:59:49

Python 2.1 发行说明 似乎解释了为什么存在此限制:

这一变化的一个副作用是
from 模块 import * 和 exec
言论已被认定为非法
在一定的函数作用域内
状况。 Python 参考
手册一直说从
模块导入*仅在以下位置合法
模块的顶层,但 CPython
解释器从未强制执行此操作
前。作为实施的一部分
嵌套范围,编译器
将Python源代码转换为字节码
生成不同的代码来访问
包含范围内的变量。从
模块导入 * 并执行使其成功
编译器不可能计算出
这是因为他们添加了名字
本地命名空间是
在编译时不可知。所以,
如果一个函数包含函数
定义或 lambda 表达式
自由变量,编译器将标记
通过引发 SyntaxError 来实现
异常。

The release notes for Python 2.1 seem to explain why this limitation exists:

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.

锦上情书 2024-09-23 04:59:49

在任何词汇层面,from amodule import * 都是一个“当时看起来是个好主意”的设计决策,但事实证明,它在现实生活中是一场真正的灾难,除了可能的例外在交互式解释器提示符处进行方便的探索(即使如此,我也不太热衷于它 - import module as m 强制仅使用两个额外的字符来使用限定名称而不是 [[只是一个 m. 前缀]]、 限定名称总是比裸名称更清晰、更灵活,更不用说在探索性交互情况下使用 m 提供巨大用处用于 help(m)reload(m) 等!)。

这种凌乱的构造使得阅读代码的穷人(通常是注定要帮助调试它)很难理解神秘出现的名称来自哪里——如果该构造在一个对象上多次使用,那么这是不可能的。词汇水平;但即使只使用一次,每次都会迫使人们费力地重新阅读整个模块,然后才能说服自己,是的,那个脏兮兮的裸名一定来自该模块。

另外,模块作者通常不会为了“支持”相关的可怕构造而费尽心思。如果您在代码中的某个地方使用了 sys.argv(当然,在模块的最顶部还有一个 import sys),您会如何做知道 sys 是它应该是的模块...或者来自 ... import *< 的一些完全不同的模块(或非模块) /代码>?!将其乘以您使用的所有限定名称,痛苦就是唯一的最终结果 - 并且神秘的错误需要长时间、费力的调试(通常需要那些确实“得到”的人的不情愿的帮助“ Python...!-)。

在函数内,添加和覆盖任意本地名称的方法会更糟糕。作为一种基本但重要的优化,Python 编译器会在函数体周围查找每个裸名称上的任何赋值或其他绑定语句,并将其看到的因此分配的名称视为“本地”(其他名称必须是全局或内置名称)。使用 import * (就像使用 exec somestring 没有显式字典用作名称空间一样),突然之间,哪些名称是本地名称,哪些名称是全局名称完全变成了一个谜 - - 因此,糟糕的编译器必须对每个名称查找采用最慢的策略,对局部变量使用字典(而不是通常使用的紧凑“向量”),并对每个引用的裸名执行最多三个字典查找,一遍又一遍。

转到任何 Python 交互式提示。输入导入此。你看到了什么? Python 之禅。该文本中最后的、可能是最伟大的智慧是什么……?

命名空间是一个非常棒的主意
-- 让我们做更多这样的事情!

通过在限定名称​​如此更可取的情况下强制使用裸名,您实际上是在做与此明智建议完全相反的事情:而不是欣赏命名空间的伟大和喇叭声,并且做更多这些,您分解两个完美且随时可用的名称空间(您正在导入的模块的名称空间,以及您正在导入的词法范围的名称空间) in) 制造出单一的、邪恶的、有缺陷的、缓慢的、僵化的、无法使用的混乱。

如果我可以回去改变Python中的一个早期设计决策(这是一个艰难的选择,因为使用def,尤其是lambda来做什么Javascript 更易读地调用 function 紧随其后;-),我会追溯地从 Guido 的脑海中消除 import * 的想法。在交互式提示下进行探索的任何所谓的便利都无法平衡它所造成的邪恶......!-)

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 possible exception of handy exploration at the interactive interpreter prompt (even then, I'm not too hot on it -- import module as m forces only two extra characters to use qualified names instead [[just an m. prefix]], and qualified names are always sharper and more flexible than barenames, not to mention the great usefulness in exploratory interactive situations of having m available for help(m), reload(m), and the like!).

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 sys at the very top of your module, of course), how do you know that sys is 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...!-).

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 somestring without 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.

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...?

Namespaces are one honking great idea
-- let's do more of those!

By forcing the use of barenames where qualified names are so vastly preferable, you're essentially doing the very opposite of this wise recommendation: instead of admiring the greatness and honkingtude of namespaces, and doing more of those, you're breaking down two 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.

If I could go back and change one early design decision in Python (it's a hard choice, because the use of def and especially lambda for what Javascript so much more readably calls function is a close second;-), I would retroactively wipe out the import * idea from Guido's mind. No amount of alleged convenience for exploration at the interactive prompt can balance the amount of evil it's wrought...!-)

薄情伤 2024-09-23 04:59:49

这并不被禁止,因为...

...它对于快速脚本和 shell 探索很方便。

...但你不应该将它保留在任何严肃的代码中

  1. 它可能会导致导入你不知道的名称并删除本地名称,
  2. 你不知道代码中使用了什么,这很难了解脚本依赖项
  3. 代码补全将不再正常工作
  4. IDE 方便的检查(例如“此 var 尚未声明”)不再起作用
  5. 它使创建循环导入变得更容易

It's not prohibited, because...

... it's handy for quick scripts and shell exploring.

...but you should not keep it in any serious code

  1. it can lead in importing names you don't know about and erase local names
  2. you can't know what's in use in your code, it's hard to know a script dependencies
  3. code completions won't work correctly anymore
  4. IDE convenient checks like "this var has not been declared" can't work anymore
  5. it make easier to create circular imports
我纯我任性 2024-09-23 04:59:49

它根本不被禁止。它工作正常,但你会收到警告,因为这通常是一个坏主意(由于其他人已经研究过的原因)。如果您愿意,您可以抑制该警告;警告模块正是您想要的。

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.

御守 2024-09-23 04:59:49

其他人已经给出了深入的答案,我将给出我的理解的简短概述答案..当您使用它时,您可以直接调用您导入的模块中的任何函数,而无需执行 modulename.functioname (您可以只调用“functionname”)如果你在不同的模块中有两个同名的函数,这会产生问题,并且在处理很多函数时也会造成混乱,因为你不知道它属于哪个对象/模块(从有人查看不熟悉的已编写代码)

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文