Mutability, Locality, and Looping
本问题已经有最佳答案,请猛点这里访问。
我有一些来自初学者编码练习的代码:
1 2 3 4 5 6 7 8 9 | numbers = [] i = 0 def populate(maximum, step): while i < maximum: numbers.append(i) i = i + step populate(10, 2) |
堆栈跟踪失败:
1 2 3 4 5 6 | 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 是一个int,因此是不变的,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行遇到实际问题(
这段代码在正确的位置失败:
1 2 3 | def populate(maximum, step): while i < maximum: raise Exception("foo") |
堆栈跟踪:
1 2 3 4 5 6 | 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 |
另一个注意事项:只有当变量在控制块的开始部分使用时(即
易变性在这里是一条红鲱鱼。可变值受作用域影响的方式与不可变值相同。实际上,在Python语言中,没有任何东西专门处理可变的值(然而,这是一个常见的神话)。
关键的洞察是,名称的作用域在每个作用域中都是固定的。在
只能从封闭范围中查找只读名称。但是,对作用域内任何位置的名称的赋值会强制将其作为作用域内任何位置的局部变量来处理。(除非使用
因此,如果您在方法的任何地方给
1 | global i |