nonlocal不能修改全局变量,因其作用域仅限直接外层函数,不包含模块级作用域;若目标变量未在紧邻外层函数中定义,会报syntaxerror;且nonlocal声明必须位于函数体开头、赋值前,不可重复声明。

nonlocal 为什么不能修改全局变量
nonlocal 的作用范围仅限于**直接外层函数作用域**,不包括模块(全局)作用域。如果误以为它能跳过一层直接改全局变量,会触发 SyntaxError: no binding for nonlocal 'x' found。
常见错误写法:
x = 10
def outer():
def inner():
nonlocal x # ❌ 报错:x 在 outer 中未定义
x = 20
正确做法是:确保目标变量在**紧邻的外层函数中被定义并赋值**,否则 nonlocal 找不到绑定目标。
nonlocal 必须在赋值前声明
Python 要求所有使用 nonlocal 声明的变量,在当前函数中**必须有且仅有一次声明**,且该声明必须出现在任何对该变量的读/写操作之前。否则会报 SyntaxError: name is assigned to before nonlocal declaration。
错误示例:
def outer():
x = 100
def inner():
print(x) # ❌ 先读再声明 → 报错
nonlocal x
x += 1
正确写法:
def outer():
x = 100
def inner():
nonlocal x
print(x) # ✅ 声明后读取
x += 1
- 声明位置必须在函数体开头附近,不能被条件或循环包裹
- 即使只读不写,只要用了
nonlocal,就必须先声明 - 不能对同一个变量多次
nonlocal声明(语法不允许)
和 global 的关键区别在哪
global 和 nonlocal 都用于突破作用域限制,但定位逻辑完全不同:
-
global x→ 搜索顶层模块作用域中的x,不管中间嵌套多少层 -
nonlocal x→ **只搜索最近一层外层函数作用域**,找到第一个就停,不会继续往外跳
例如:
x = "module"
def f():
x = "f"
def g():
x = "g"
def h():
nonlocal x
x = "h modified" # ✅ 改的是 g 中的 x
h()
print(x) # 输出 "h modified"
g()
如果把 nonlocal x 换成 global x,则最终修改的是最外层的 x = "module"。
闭包变量被修改后,闭包对象是否同步更新
是的。只要变量通过 nonlocal 修改,所有引用它的闭包(比如返回的内层函数)都会看到新值——因为它们共享同一块栈帧中的局部变量存储位置。
典型验证场景:
def make_counter():
count = 0
def inc():
nonlocal count
count += 1
return count
def get():
return count
return inc, get
<p>inc, get = make_counter()
print(inc()) # 1
print(get()) # 1 ← 与 inc 共享同一个 count</p>
注意:这种共享是“实时”的,但前提是闭包对象仍持有对外层函数栈帧的引用。一旦外层函数执行结束且无引用保留,该帧会被回收,nonlocal 就失去意义了。
真正容易被忽略的是:如果外层函数返回多个闭包,它们修改的是**同一个变量实体**,不是各自副本。这点在实现状态机、计数器、缓存等逻辑时,直接影响行为一致性。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











