可变性、局部性和循环

Mutability, Locality, and Looping

我有一些来自初学者编码练习的代码:

numbers = []
i = 0

def populate(maximum, step):
    while i < maximum:
        numbers.append(i)
        i = i + step

populate(10, 2)

堆栈跟踪失败:

Traceback (most recent call last):
    File "test_python.py", line 9, in <module>
        populate(10, 2)
    File "test_python.py", line 5, in populate
        while i < maximum:
UnboundLocalError: local variable 'i' referenced before assignment

这是我目前对问题的理解...

那么我的问题是,为什么 Python 在遇到第 5 行的 while 循环时失败,而不是第 7 行的实际问题 (i = i + 1)?这是解释器将 while 循环作为代码块的产物吗?

这段代码在正确的地方失败了:

def populate(maximum, step):
    while i < maximum:
        raise Exception("foo")

堆栈跟踪:

Traceback (most recent call last):
    File "test_python.py", line 12, in <module>
        populate(10, 2)
    File "test_python.py", line 6, in populate
        raise Exception("foo")
Exception: foo

另一个注意事项:这似乎只有在控制块的开头使用变量时才会出现这种情况(即 while i < maximum)。每种类型的控制块都会出现相同的行为:while、for、if、elif 等。

可变性在这里是一个转移注意力的问题。可变值受作用域的影响与不可变值的影响方式相同。事实上,Python 语言中的 nothing 专门处理可变值(然而,这是一个常见的神话)。

关键的见解是名称的范围在每个范围内都是固定的。在 populate 的范围内, 每个 名称必须是本地的或全局的:此决定是方法字节码的一部分。

可以从封闭范围中查找只能读取的名称。但是,对范围内任何位置的名称的赋值会强制将其视为范围内 everywhere 的局部变量。 (除非您使用 globalnonlocal 关键字。)

因此,如果您在方法中将 i anywhere 赋值,则 i 必须是该方法的局部新变量,而不是全球 i。如果您希望 i 表示全局 i,只需在方法顶部添加此行:

global i