Python函数作用域名字空间,locals的原理。
最近在回看《Python学习笔记》看到函数这一章节,书中P153页。
书中介绍了函数的每次调用,都会新建栈帧,用于局部变量和执行过程的存储。
等执行结束,栈帧内存被回收,同时释放相关对象。
以字典实现的名字空间,虽然灵活,但存在访问效率低下等问题。这对于使用频率较低的模块名字空间尚可,可对于有性能要求的函数调用,显然就是瓶颈所在。
为此,解释器划出专门的内存空间,用效率最快的数组代替字典。在函数指令执行前,先将包含参数在内的所有局部变量,以及要使用的外部变量复制(指针)到该数组。
基于作用域不同,此内存区域可简单分为两部分:FAST和DEREF
如此,操作指令只需要索引既可理解读取或存储目标对象,这远比哈希查找过程高效很多。从dis可以看出来,load读取操作的都是索引。
空间名字
那locals函数返回的东西是哪里来的,locals函数产生的字典是按需延迟创建,并从FAST区域复制相关信息得来的。
def test(): x = 100 locals()['x'] = 999 print('fast.x =', x) print('local.x =', locals()['x']) test()
输出
fast.x = 100
local.x = 100
从输出就可以看出来,locals并不能改变函数局部作用域的命名空间,这个一个单线的操作,每次都会从函数的命名空间的元祖生成一个字典,
可能是为了对应globals吧,也可能为了格式的统一显式。
这个Python的底层还真的有意思。