You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python函数g()局部命名空间含f_var的原因及移除print后的疑问

Python局部命名空间与locals()的疑问

我从Python文档了解到,函数的局部命名空间在函数被调用时创建。但在以下测试代码中,调用locals()获取函数g()的局部命名空间(字典类型)时,结果里居然包含了标识符f_var——这个变量在g()函数体内是出现在locals()调用之后的代码中的。更奇怪的是,移除print(f_var)这一行后,locals()返回的字典里就不再有f_var了。

测试代码

# local_namespace_test.py
def f():
    f_var = 55

    def g():
        g_var = 3
        print(f"locals in g(): {locals()}")
        print(f_var)
        return

    g()
    return

f()

正常运行输出

$ python3 local_namespace_test.py 
locals in g(): {'g_var': 3, 'f_var': 55}
55

注释掉print(f_var)后的输出

$ python3 local_namespace_test.py 
locals in g(): {'g_var': 3}

疑问

  • 为什么此场景下g()的局部命名空间会包含f_var?
  • 为什么移除print(f_var)后,locals()返回的字典中就不再有f_var?

解答

这背后是Python编译阶段的变量解析规则在起作用:

  1. 编译期确定变量集合:Python在编译函数g()的时候,会扫描整个函数体的代码,找出所有需要引用的变量。当代码里有print(f_var)时,f_var会被识别为自由变量(即不在g()局部作用域定义、需要从外层作用域f()中获取的变量),这个信息会被记录在函数的闭包结构里。

  2. locals()的返回内容:locals()函数返回的字典,不仅包含当前函数的局部变量(比如g_var),还会包含函数编译时确定的所有自由变量。哪怕locals()的调用在print(f_var)之前,因为编译阶段已经确定g()需要引用f_var,所以调用g()时,这个自由变量会被纳入到locals()返回的字典中。

  3. 移除引用后的变化:如果删掉print(f_var)这行,g()的代码里不再引用f_var,编译阶段就不会把它标记为自由变量。此时g()的局部命名空间里只有自己定义的g_var,locals()自然也就不会返回f_var了。

简单来说,locals()的内容不是按代码执行顺序动态生成的,而是基于函数编译时确定的变量集合来构建的——只要函数体里存在对外部变量的引用,哪怕引用在locals()之后,这个变量也会出现在locals()的结果里。

内容的提问来源于stack exchange,提问作者gambarimas87

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 17:20:31