1. nonlocal 是什么?

nonlocal 用于在嵌套函数中声明变量来自外层函数作用域(非全局),使得可以在内层函数中修改外层函数的变量。

def outer():
    x = 10
    
    def inner():
        nonlocal x  # 声明 x 来自外层函数
        x = 20      # 现在可以修改外层函数的 x
    
    inner()
    print(x)  # 输出:20

2. 什么时候需要使用 nonlocal

① 重新赋值不可变对象

def outer():
    count = 0  # 不可变对象
    
    def increment():
        nonlocal count  # 必须使用!
        count += 1      # 重新赋值不可变对象
        return count
    
    return increment

② 重新绑定可变对象

def outer():
    lst = [1, 2, 3]  # 可变对象
    
    def inner():
        nonlocal lst  # 必须使用!
        lst = [4, 5, 6]  # 重新绑定到新的列表
    
    inner()
    print(lst)  # [4, 5, 6]

3. 什么时候不需要使用 nonlocal

① 只读取外层变量(不修改)

def outer():
    x = 10
    def inner():
        print(x)  # 只需要读取,不需要 nonlocal
    inner()

② 修改可变对象的内容

def outer():
    lst = [1, 2, 3]  # 可变对象
    
    def inner():
        lst.append(4)     # 修改列表内容,不需要 nonlocal
        lst[0] = 100      # 修改元素,不需要 nonlocal
    
    inner()
    print(lst)  # [100, 2, 3, 4]

4. 可变对象 vs 不可变对象

🔄 可变对象 (Mutable)

创建后内容可以被修改的对象:

  • 列表 list[1, 2, 3]
  • 字典 dict{'a': 1}
  • 集合 set{1, 2, 3}
  • 自定义对象:用户定义的类实例

🔒 不可变对象 (Immutable)

创建后内容不能被修改的对象:

  • 数字int, float
  • 字符串 str"hello"
  • 元组 tuple(1, 2, 3)
  • 布尔值 boolTrue, False
  • 冻结集合 frozenset

总结规则

操作 是否需要 nonlocal 例子
读取变量 ❌ 不需要 print(x)
修改可变对象内容 ❌ 不需要 lst.append(1), dict['key'] = value
重新赋值不可变对象 ✅ 需要 x = 10, count += 1
重新绑定可变对象 ✅ 需要 lst = [1,2,3], dict = {'a': 1}

简单记忆:只有使用 = 进行赋值操作时才需要 nonlocal,无论对象是可变的还是不可变的。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐