我从初学者的编码练习中得到了一些代码:
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
到目前为止,这是我对问题的理解...
i
是一个整数,因此是不可变的,而numbers
是一个列表并且是可变的i
是不可变的,因此可以在超出范围的情况下对其进行读取。但是,如果不在范围内(即在populate
函数中)覆盖它,则会导致UnboundLocalError
numbers
是可变列表,因此附加到列表不会引起覆盖,因此不会导致UnboundLocalError
如果对populate
方法进行了简单的更改,程序将成功运行(由于i
未被覆盖)
def populate(maximum, step):
new_i = i
while new_i < maximum:
numbers.append(i)
new_i = new_i + step
如果我注释掉i = i + 1
行,则while循环(显然)将永远运行,但是程序不会失败。
然后我的问题是,为什么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等。
答案 0 :(得分:3)
此处的可移植性是一个红鲱鱼。可变值受范围影响的方式与不可变值相同。实际上,Python语言中的 nothing 不会专门处理可变值(但这是一个普遍的神话)。
关键见解是名称的范围在每个范围中都是固定的。在populate
范围内,每个名称都必须是本地名称或全局名称:此决定是方法字节码的一部分。
可以从封闭的范围中查找只能读取的名称。但是,对范围内任何位置的名称赋值会强制将其视为范围内 everywhere 的局部变量。 (除非您使用global
或nonlocal
关键字。)
因此,如果您要在方法中的任何地方分配给i
,那么i
必须是该方法局部的新变量,而不是全局变量{{1 }}。如果要i
表示全局i
,只需在方法顶部添加以下行:
i