python - 在此示例中,名称 *open* 属于内置作用域还是全局作用域?

标签 python scope global lookup built-in

考虑这个代码片段:

global open
print(open)

给出以下结果:

<built-in function open>

我的问题是:在此示例中,名称 open 属于内置范围还是全局范围?

我认为全局声明将强制名称 open 映射到全局范围(因此,将导致错误),但这里没有发生这种情况。为什么?

最佳答案

首先,直接回答:

名称open属于顶级命名空间。这本质上意味着“在全局变量中查找,回退到内置变量;分配给全局变量”。

添加global open只会强制它属于它已经所在的顶级命名空间。 (我假设这是顶级代码,而不是在函数或类中。)

这似乎与您所读到的内容有所不同吗?嗯,有点复杂。


根据the reference docs:

The global statement is a declaration which holds for the entire current code block. It means that the listed identifiers are to be interpreted as globals.


但是,尽管文档的其他部分似乎暗示了这一点,“解释为全局变量”实际上并不意味着“在全局命名空间中搜索”,而是“在顶级命名空间中搜索”,如 Resolution of names 中所述:

Names are resolved in the top-level namespace by searching the global namespace, i.e. the namespace of the module containing the code block, and the builtins namespace, the namespace of the module builtins. The global namespace is searched first. If the name is not found there, the builtins namespace is searched.

“as globals”的意思是“与全局命名空间中的名称查找方式相同”,也称为“在顶级命名空间中”。

当然,对顶级命名空间的分配总是分配给全局变量,而不是内置变量。 (这就是为什么您可以首先使用全局 open 隐藏内置 open 的原因。)


另外,请注意,正如 exec and eval 文档中所解释的,对于通过 exec 运行的代码来说,甚至也不太正确:

If the globals dictionary does not contain a value for the key __builtins__, a reference to the dictionary of the built-in module builtins is inserted under that key. That way you can control what builtins are available to the executed code by inserting your own __builtins__ dictionary into globals before passing it to exec().

exec 最终是模块和脚本的执行方式。

因此,真正发生的情况(至少在默认情况下)是搜索全局命名空间;如果未找到该名称,则在全局命名空间中搜索 __builtins__ 值;如果这是一个模块或映射,则会对其进行搜索。


如果您特别好奇这在 CPython 中是如何工作的:

  • 编译时:
    • 编译器为函数构建符号表,将名称分为 freevars(非局部变量)、cellvars(嵌套函数用作非局部变量的局部变量)、局部变量(任何其他局部变量)和全局变量(当然,从技术上讲,这意味着“顶级命名空间”变量)。这就是 global 语句发挥作用的地方:它强制将名称添加到全局符号表中,而不是其他符号表中。
    • 然后它编译代码,并为全局变量发出 LOAD_GLOBAL 指令。 (它将各种名称存储在代码对象的元组成员中,例如用于全局变量的 co_names 和用于单元变量的 co_cellvars 等等。)
  • 运行时:
    • 当从编译代码创建函数对象时,它会作为属性附加到它上面。
    • 调用函数时,其 __globals__ 将成为框架的 f_globals
    • 然后,解释器的 eval 循环会按照您对 f_globals 的预期执行操作来处理每个 LOAD_GLOBAL 指令,包括回退到 __builtins__exec 文档中所述。

关于python - 在此示例中,名称 *open* 属于内置作用域还是全局作用域?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51887533/

相关文章:

javascript - 当变量定义非常明确时,事件监听器抛出 "Undefined"错误

python - 从函数内更改全局变量?

python - 更改张量某一列的值

javascript - 多次调用 javascript 会导致 setInterval 永远不会被清除

python - 如何将数据框/列表写入 csv 文件?

java - Spring 4 @Service 和 @RequestScope

JavaScript 更新一个全局变量

python - 如何在 Python 中将全局标记为已弃用?

python2.7 多进程池异步与同步

python - 转置列表