三层嵌套函数中最内层函数为何能访问最外层函数的命名空间?
为什么嵌套函数能访问外层函数的局部变量?
先看你写的这段测试代码:
>>> def f(): f=['f',1,2] def g(): g=1 print('this prints out f from f(): ',f) print("id",id(f)) def x(): x=1 print('this also prints out f from f():',f) print('id',id(f)) x() g() >>> f() #output this prints out f from f(): ['f', 1, 2] id 140601546763464 this also prints out f from f(): ['f', 1, 2] id 140601546763464
你的猜测完全正确!Python在查找变量时,封闭命名空间会递归遍历所有外层嵌套的函数作用域,这背后是Python的「作用域链(Scope Chain)」机制,核心遵循LEGB命名空间查找规则:
- L(Local):优先查找当前函数的局部命名空间
- E(Enclosing):如果局部没找到,就递归向外查找所有包裹当前函数的外层嵌套函数的命名空间
- G(Global):接着查找模块级的全局命名空间
- B(Built-in):最后查找Python内置的命名空间(比如
print、len这类内置函数)
回到你的代码:x()和g()的局部作用域里没有定义f,所以Python自动向外遍历它们的封闭作用域——也就是包裹它们的f()函数的局部命名空间,在这里找到了f列表变量,因此能直接访问,不会报错。
这里补充个细节:如果在g()或x()里尝试给f赋值(比如f = [3,4,5]),Python会默认你是在当前函数的局部作用域定义新变量,而非修改外层的f;如果在赋值前先打印f,还会抛出UnboundLocalError(局部变量未定义就被引用)。要是想修改外层函数的f,需要用nonlocal关键字声明(Python 3+支持)。
总结来说,你观察到的现象完全符合Python的作用域规则,封闭命名空间本身就包含了所有外层嵌套的函数作用域,Python会逐层递归查找直到找到目标变量,或者遍历完所有作用域后抛出NameError。
内容的提问来源于stack exchange,提问作者spiritedExit0
相关产品推荐
相关产品推荐

