Python如何提前识别局部变量及locals()相关问题
Python局部变量识别与locals()机制解答
核心前提:Python对函数作用域内的变量归属判定,是编译函数的静态阶段完成的,不是代码运行到对应行时才临时判定。
问题1:为什么赋值语句执行前,Python就能识别到当前作用域的局部变量?
- 编译器在处理函数定义时,会全量扫描函数体内所有的名称引用与赋值操作:只要某个名称在函数体内存在赋值行为(包括普通赋值、循环变量赋值、上下文管理器变量赋值等),且没有被
global/nonlocal关键字声明为外层作用域变量,编译器就会直接将该名称标记为当前函数的局部变量,这个标记会被写入函数的代码对象元数据中,和代码运行顺序无关。 - 示例代码中,因为line4存在
x=2的赋值,编译器在编译f()时就已经把x判定为函数局部变量。运行到line3的print(x)时,Python不会按LEGB规则向外层全局作用域查找x,只会在当前局部作用域检索,此时x还未完成赋值,就会抛出UnboundLocalError。 - 你可以通过函数的代码对象属性,直接查看编译器标记的所有局部变量名,这个结果不受代码运行位置影响:
def f(): print(f.__code__.co_varnames) # 输出('x',),哪怕还没运行到x的赋值行 x = 2
问题2:既然已经识别到局部变量x,为什么locals()不返回它?
locals()的设计逻辑是返回当前执行位置下,局部作用域内已经完成值绑定(即已经赋值初始化)的变量字典,它反映的是运行时局部命名空间的实时状态,不是编译器静态标记的局部变量名清单。- 被编译器标记为局部变量的名称,只有在运行到对应赋值语句、完成值绑定之后,才会被加入局部命名空间的活动字典中。在赋值语句执行前,这个名称只是一个静态标记,没有实际绑定值,也不会进入活动命名空间,自然不会出现在
locals()的返回结果里。
常见认知偏差纠正
LEGB名称查找规则本身没有问题,但要注意:LEGB是运行时查找已确定作用域的名称时的顺序规则,而名称本身属于哪一层作用域,是编译阶段就静态确定的,不会在运行时随着代码执行动态调整。
内容的提问来源于stack exchange,提问作者Ashish Chourasia
相关产品推荐
相关产品推荐

