python:global vs nonlocal

这两者都只有在修改外部作用域变量时才需要,如果只是读取就不用

首先需要区分python中的全局变量和局部变量

全局变量是在函数外定义的变量,即所有定义在def中的变量都不是全局变量,即使是嵌套函数外层函数中定义的变量

相反,定义在函数内部的变量即为局部变量,即使闭包嵌套再多层,也都是局部变量。

如果要在函数中 修改 全局变量(即将原本的引用指向一个新的引用地址,最下面有举例说明),则需要先用 global 声明。

count = 0

def increment():
    global count  # 修改全局变量前应先声明这里的count是全局变量,否则下一行语句会报错
    count += 1
    print(count)

increment()  # 输出1
increment()  # 输出2

如果想要在闭包中修改上层函数中的变量,则需要使用 nonlocal 关键字先声明,它的作用和 global 类似,但是它只能关联嵌套函数中上层函数中的变量。

def outer():
    count = 0

    def increment():
        nonlocal count  # 使用nonlocal声明这里的count是上层函数中的count
        count += 1
        print(count)

    increment()  # 输出1
    increment()  # 输出2
outer()

注意:即使上层函数中没有引用的变量,但是上上层有,或者更上层有,也是可以的:

def outer():
    count = 0
    def inner():
        def increment():
            nonlocal count  # 使用nonlocal声明这里的count是上上层函数中的count
            count += 1
            print(count)

        increment()  # 输出1
        increment()  # 输出2
    inner()
outer()

但是nonlocal引用的变量必须是局部变量(定义在函数内部),如果将上述 count=0 定义在最上层(outer()函数外面),则报错。

那么global和nonlocal可不可以组合使用呢?考虑下面代码:

count = 0
def outer():
    global count
    def increment():
        nonlocal count
        count += 1
        print(count)

    increment()  # 报错:no binding for nonlocal 'count' found
outer()

还是那句话,nonlocal引用的变量必须是局部变量,上面的代码中虽然在outer()函数中使用 global 引用了全局变量 count,但它本质上还是全局变量。

所有,要使得上述代码正确运行。只需要将 increment() 函数中的 nonlocal count 修改为 global count 即可


考虑以下代码,他们执行时会报错吗?

def f():
    count = 0
    def s():
        count = count + 1
    s()
def f():
    count = 0
    def s():
        count = 1
    s()
def f():
    arr = [1]
    def s():
        arr.append(2)
    s()

第一个会报错,后两个不会报错,原因是:

对于第二个代码:两个count是两个变量,s()函数中的count是单独创建的一个变量,而使用 += 这种操作符时就不会重新创建变量

对于第三个代码:并没有改变arr的引用,只是在原本引用的数组上添加了一个元素而已,所以 f()函数中的arr最终为 [1, 2]

Leave a Comment