可变性,局部性和循环性

时间:2018-12-19 03:43:12

标签: python python-2.7 interpreter

我从初学者的编码练习中得到了一些代码:

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等。

1 个答案:

答案 0 :(得分:3)

此处的可移植性是一个红鲱鱼。可变值受范围影响的方式与不可变值相同。实际上,Python语言中的 nothing 不会专门处理可变值(但这是一个普遍的神话)。

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

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

因此,如果您要在方法中的任何地方分配给i ,那么i必须是该方法局部的新变量,而不是全局变量{{1 }}。如果要i表示全局i,只需在方法顶部添加以下行:

i