为什么在嵌套函数中只能访问可变变量?

问题描述

这是一个简单的(没用的)函数

def f(x):
    b = [x]
    def g(a):
        b[0] -= 1
        return a - b[0]
    return g

工作正常。让我们对其稍作更改:

def f(x):
    b = x
    def g(a):
        b -= 1
        return a - b
    return g

现在,它给出一个错误,指出b未定义!当然,可以使用nonlocal解决,但是我想知道为什么会首先发生这种情况?为什么可变变量是可访问的,而可变变量是不可访问的?

解决方法

从技术上讲,它与可变或不可变无关(语言不知道类型是否为“可变”)。此处的区别在于,在一种情况下,您将分配给变量,而在另一种情况下,您将从变量中读取数据。

在第二个示例中,行b -= 1b = b - 1相同。您要分配给变量b的事实将使名为b的局部变量与名为b的外部变量分开。由于在评估分配的右侧时尚未分配局部变量b,因此从局部b读取会出现错误。

在您的第一个示例中,行b[0] -= 1b[0] = b[0] - 1相同。但这不是变量分配。那只是一个列表元素访问。它只是b.__setitem__(0,b.__getitem__(0) - 1)的语法糖。您这里没有分配变量b,您要做的只是从变量b读取两次(以便在其指向的对象上调用方法)。由于您仅从b中读取内容,因此它使用外部变量b

如果在第一个示例中,使用可变列表,像在第二个示例中一样,进行了变量赋值,则将同样创建一个局部变量,并且在赋值之前读取该局部变量也将不起作用:

def f(x):
    b = [x]
    def g(a):
        b = [b[0] - 1]
        return a - b[0]
    return g