Python:为什么禁止“from <module> import *”?

2025-04-10 09:47:00
admin
原创
23
摘要:问题描述:如果你碰巧有from <module> import * 在程序(或模块)的中间,你会收到警告:/tmp/foo:100: SyntaxWarning: import * only allowed at module level 我理解为什么import *一般不鼓励这样做(命名空间不可...

问题描述:

如果你碰巧有

from <module> import *

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

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

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

那么,有人可以详细解释为什么from <module> import *在所有可能的情况下都应该禁止吗?


解决方案 1:

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

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

这是不允许的,因为这会使优化函数体变得太难。Python 实现希望在对函数进行字节编译时知道所有函数局部变量的名称,以便它可以将变量引用优化为 (CPython) 虚拟机操作数堆栈上的操作,或者至少优化为局部变量槽操作,而不是在外部命名空间中查找。如果您可以将模块的全部内容转储到函数的本地命名空间中,那么编译器必须假定函数中的任何名称都可能引用模块全局变量,因为引入的名称列表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 中的新增功能”中的同一段。现在大家去投票吧。

解决方案 2:

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

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

解决方案 3:

在任何词汇层面上,from amodule import *这都是一个“当时看似是个好主意”的设计决策,但在现实生活中却被证明是一场真正的灾难,除了交互式解释器提示下进行方便的探索之外(即使在那时,我也不太喜欢它——import module as m强制只有两个额外的字符使用限定名称而不是[[只是一个m.前缀]],并且限定名称总是比裸名更清晰、更灵活,更不用说在探索性交互情况下有mhelp(m)reload(m)可用的巨大用处!)。

这种混乱的结构让阅读代码的可怜人(通常是为了帮助调试而徒劳无功)很难理解这些神秘名称的来源——如果这种结构在词汇层面上使用多次,这是不可能的;但即使只使用一次,每次也不得不费力地重读整个模块,然后才能说服自己,是的,那个混乱的光秃秃的名字一定来自这个模块。

此外,模块作者通常不会费尽心思去“支持”有问题的可怕构造。如果您的代码中某个地方有一个使用sys.argvimport sys当然,在模块的最顶部),您怎么知道sys应该是哪个模块……或者来自的某个完全不同的模块(或非模块) ?!将它乘以您使用的所有合格名称,唯一的最终结果就是痛苦——那就是神秘的错误,需要长时间、费力的调试(通常是在不情愿的情况下,在“了解... import *”Python的人的帮助下……!-)。

在函数中,添加和覆盖任意本地名称的方法会更糟糕。作为一项基本但关键的优化,Python 编译器会在函数主体中查找每个 barename 上的任何赋值或其他绑定语句,并将它看到的已赋值的名称视为“本地”(其他名称必须是全局或内置的)。使用 an import *(就像使用 an 而不使用显式字典作为命名空间一样exec somestring),突然间,哪些名称是本地的,哪些名称是全局的就完全成了一个谜——因此,可怜的编译器不得不对每次名称查找都采取最慢的策略,使用字典来表示局部变量(而不是它通常使用的紧凑“向量”),并一遍又一遍地对引用的每个 barename 执行最多三次字典查找。

转到任何 Python 交互式提示。输入import this。你看到了什么?Python 之禅。该文本中最后一个也是最伟大的智慧是什么......?

命名空间是一个非常好的主意——让我们多做一些这样的事!

通过在限定名称非常可取的地方强制使用裸名,您实际上是在做与这一明智建议完全相反的事情:您不是欣赏命名空间的伟大和优雅,也不是更多地这样做,而是破坏了两个完好无损且可立即使用的命名空间(您正在导入的模块的命名空间和您正在导入它的词法范围的命名空间),从而形成一个邪恶、有缺陷、缓慢、僵化、无法使用的混乱局面。

如果我可以回到过去并改变Python 的一个早期设计决策(这是一个艰难的选择,因为使用def和,尤其是lambda对于可读性更强的 JavaScript 调用来说,function是紧随其后的;-),我会追溯性地从 Guido 的脑海中抹去这个想法。在交互式提示符下进行探索的所谓import *便利性再多也无法抵消它造成的邪恶程度……!-)

解决方案 4:

这并没有被禁止,因为......

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

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

  1. 它可能会导致引入你不了解的名称并抹去本地名称

  2. 你无法知道代码中使用了什么,很难知道脚本的依赖关系

  3. 代码补全将不再正常工作

  4. IDE 中诸如“此变量尚未声明”之类的便捷检查不再起作用

  5. 使创建循环导入更加容易

解决方案 5:

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

解决方案 6:

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

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用