考虑这个代码片段:
global open
print(open)
给出以下结果:
<built-in function open>
我的问题是:在此示例中,名称 open 属于内置范围还是全局范围?
我认为全局声明将强制名称 open 映射到全局范围(因此,将导致错误),但这里没有发生这种情况。为什么?
最佳答案
首先,直接回答:
名称open
属于顶级命名空间。这本质上意味着“在全局变量中查找,回退到内置变量;分配给全局变量”。
添加global open
只会强制它属于它已经所在的顶级命名空间。 (我假设这是顶级代码,而不是在函数或类中。)
这似乎与您所读到的内容有所不同吗?嗯,有点复杂。
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, thebuiltins
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 modulebuiltins
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 toexec()
.
而 exec
最终是模块和脚本的执行方式。
因此,真正发生的情况(至少在默认情况下)是搜索全局命名空间;如果未找到该名称,则在全局命名空间中搜索 __builtins__ 值;如果这是一个模块或映射,则会对其进行搜索。
如果您特别好奇这在 CPython 中是如何工作的:
- 编译时:
- 编译器为函数构建符号表,将名称分为 freevars(非局部变量)、cellvars(嵌套函数用作非局部变量的局部变量)、局部变量(任何其他局部变量)和全局变量(当然,从技术上讲,这意味着“顶级命名空间”变量)。这就是
global
语句发挥作用的地方:它强制将名称添加到全局符号表中,而不是其他符号表中。 - 然后它编译代码,并为全局变量发出
LOAD_GLOBAL
指令。 (它将各种名称存储在代码对象的元组成员中,例如用于全局变量的co_names
和用于单元变量的co_cellvars
等等。)
- 编译器为函数构建符号表,将名称分为 freevars(非局部变量)、cellvars(嵌套函数用作非局部变量的局部变量)、局部变量(任何其他局部变量)和全局变量(当然,从技术上讲,这意味着“顶级命名空间”变量)。这就是
- 运行时:
- 当从编译代码创建函数对象时,它会作为属性附加到它上面。
- 调用函数时,其
__globals__
将成为框架的f_globals
。 - 然后,解释器的 eval 循环会按照您对
f_globals
的预期执行操作来处理每个LOAD_GLOBAL
指令,包括回退到__builtins__
如exec
文档中所述。
关于python - 在此示例中,名称 *open* 属于内置作用域还是全局作用域?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51887533/