yua*_*210 2 python lookup scope global built-in
请考虑以下代码段:
global open
print(open)
Run Code Online (Sandbox Code Playgroud)
得出以下结果:
<built-in function open>
Run Code Online (Sandbox Code Playgroud)
我的问题是:在这个例子中,名称open是否属于内置或全局范围?
我认为全局声明会强制将name 打开映射到全局范围(因此,会导致我们出错),这不会发生在这里.为什么?
一,直接回答:
该名称open属于顶级命名空间.这本质上意味着"查找全局变量,回退到内置函数;分配给全局变量".
添加global open只是强制它属于顶级命名空间,它已经存在.(我假设这是顶级代码,而不是函数或类.)
这似乎与你读到的内容有关吗?嗯,这有点复杂.
根据参考文档:
该
global语句是一个声明,它适用于整个当前代码块.这意味着列出的标识符将被解释为全局变量.
但是,尽管文档的其他部分似乎暗示,"解释为全局"实际上并不意味着"在全局命名空间中搜索",而是"在顶级命名空间中搜索",如名称解析中所述:
通过搜索全局命名空间(即包含代码块的模块的命名空间)和内置命名空间(模块的命名空间),在顶级命名空间中解析名称
builtins.首先搜索全局命名空间.如果在那里找不到builtins名称,则搜索名称空间.
并且"作为全局变量"意味着"与查找全局名称空间中的名称的方式相同",即"在顶级名称空间中".
当然,对顶级命名空间的赋值总是归于全局变量,而不是内置变量.(这就是为什么你可以首先open用全局影响内置的open.)
另外,请注意,正如在exec和eval文档中所解释的那样,对于运行的代码来说,即使这样也不是这样exec:
如果全局字典不包含键的值,则在该键下插入
__builtins__对内置模块的字典的引用builtins.这样,您可以通过__builtins__在传递给自己的字典之前将自己的字典插入到globals中来控制已执行代码可用的内置函数exec().
并且exec最终是如何执行模块和脚本的.
所以,真正发生的事情 - 至少在默认情况下 - 是搜索全局命名空间; 如果找不到该名称,则在全局名称空间中搜索一个__builtins__值; 如果那是模块或映射,则搜索它.
如果你很好奇CPython的工作原理:
global语句发挥作用的地方:它强制将名称添加到全局符号表而不是另一个.LOAD_GLOBAL全局变量的指令.(它将各种名称存储在代码对象的元组成员中,如co_names全局变量和单元co_cellvars格等等.)__globals__它将作为属性附加到它.__globals__变成f_globals了框架.LOAD_GLOBAL通过完全按照您的期望来处理每条指令f_globals,包括文档中__builtins__描述的回退exec.