名称 *open* 属于本例中的内置作用域还是全局作用域?
Does the name *open* belong to the built-in or the global scope in this example?
考虑这个代码片段:
global open
print(open)
结果如下:
<built-in function open>
我的问题是:名称open在这个例子中属于内置作用域还是全局作用域?
我认为全局声明会强制将名称 open 映射到全局范围(因此会导致我们出错),但这并没有发生这里。为什么?
第一,直接回答:
名称open
属于顶级命名空间。这实质上意味着 "look up in globals, fallback to builtins; assign to globals"。
添加 global open
只是强制它属于顶级名称空间,它已经存在。 (我假设这是顶级代码,不在函数内部或 class。)
这似乎与您阅读的内容相符吗?嗯,有点复杂。
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.
但是,尽管文档的其他部分似乎暗示了什么,"interpreted as globals" 实际上并不意味着 "searched in the global namespace",而是 "searched in the top-level namespace",如 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" 表示 "the same way that names in the global namespace are looked up",又名 "in the top-level namespace"。
而且,当然,对顶级命名空间的分配始终是全局变量,而不是内置变量。 (这就是为什么你可以首先使用全局 open
隐藏内置 open
。)
此外,请注意,如 exec
and eval
文档中所述,即使 this 对于代码 运行 到 [=17= 也不完全正确]:
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 中是如何工作的:
- 编译时:
- 编译器为函数构建一个符号 table,将名称分成 freevars(非局部变量)、cellvars(被嵌套函数用作非局部变量的局部变量)、局部变量(任何其他局部变量)和全局变量 (这当然在技术上意味着 "top-level namespace" 变量)。这就是
global
语句发挥作用的地方:它强制将名称添加到全局符号 table 而不是其他符号。
- 然后它编译代码,并为全局变量发出
LOAD_GLOBAL
指令。 (并且它将各种名称存储在代码对象的元组成员中,例如 co_names
用于全局变量,co_cellvars
用于 cellvars 等等。)
- 在运行时间:
- 当从编译代码创建函数对象时,它会
__globals__
作为属性附加到它。
- 当一个函数被调用时,它的
__globals__
变成框架的 f_globals
。
- 解释器的 eval 循环然后通过完全按照您对
f_globals
的期望来处理每个 LOAD_GLOBAL
指令,包括回退到 __builtins__
,如 [=17] 中所述=] 文档。
考虑这个代码片段:
global open
print(open)
结果如下:
<built-in function open>
我的问题是:名称open在这个例子中属于内置作用域还是全局作用域?
我认为全局声明会强制将名称 open 映射到全局范围(因此会导致我们出错),但这并没有发生这里。为什么?
第一,直接回答:
名称open
属于顶级命名空间。这实质上意味着 "look up in globals, fallback to builtins; assign to globals"。
添加 global open
只是强制它属于顶级名称空间,它已经存在。 (我假设这是顶级代码,不在函数内部或 class。)
这似乎与您阅读的内容相符吗?嗯,有点复杂。
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.
但是,尽管文档的其他部分似乎暗示了什么,"interpreted as globals" 实际上并不意味着 "searched in the global namespace",而是 "searched in the top-level namespace",如 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" 表示 "the same way that names in the global namespace are looked up",又名 "in the top-level namespace"。
而且,当然,对顶级命名空间的分配始终是全局变量,而不是内置变量。 (这就是为什么你可以首先使用全局 open
隐藏内置 open
。)
此外,请注意,如 exec
and eval
文档中所述,即使 this 对于代码 运行 到 [=17= 也不完全正确]:
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 中是如何工作的:
- 编译时:
- 编译器为函数构建一个符号 table,将名称分成 freevars(非局部变量)、cellvars(被嵌套函数用作非局部变量的局部变量)、局部变量(任何其他局部变量)和全局变量 (这当然在技术上意味着 "top-level namespace" 变量)。这就是
global
语句发挥作用的地方:它强制将名称添加到全局符号 table 而不是其他符号。 - 然后它编译代码,并为全局变量发出
LOAD_GLOBAL
指令。 (并且它将各种名称存储在代码对象的元组成员中,例如co_names
用于全局变量,co_cellvars
用于 cellvars 等等。)
- 编译器为函数构建一个符号 table,将名称分成 freevars(非局部变量)、cellvars(被嵌套函数用作非局部变量的局部变量)、局部变量(任何其他局部变量)和全局变量 (这当然在技术上意味着 "top-level namespace" 变量)。这就是
- 在运行时间:
- 当从编译代码创建函数对象时,它会
__globals__
作为属性附加到它。 - 当一个函数被调用时,它的
__globals__
变成框架的f_globals
。 - 解释器的 eval 循环然后通过完全按照您对
f_globals
的期望来处理每个LOAD_GLOBAL
指令,包括回退到__builtins__
,如 [=17] 中所述=] 文档。
- 当从编译代码创建函数对象时,它会