【问题标题】:Mutability, Locality, and Looping [duplicate]可变性、局部性和循环
【发布时间】:2018-12-19 03:43:11
【问题描述】:

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

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 是一个 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 行的实际问题 (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 &lt; maximum)。每种类型的控制块都会发生相同的行为:while、for、if、elif 等。

【问题讨论】:

  • 这个与不可变与可变无关。如果对尚未声明的名称进行赋值 globalanywhere,Python 会创建一个作用域为包含该赋值的函数的变量。
  • “因为 i 是不可变的,所以它可以在超出范围时被读取。” 不,对象的可变性对 Python 的作用域规则没有影响。这完全无关紧要。

标签: python python-2.7 interpreter


【解决方案1】:

在这里,可变性是一个红鲱鱼。可变值受作用域影响的方式与不可变值相同。事实上,Python 语言中的 nothing 专门处理可变值(不过,这是一个常见的神话)。

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

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

因此,如果您在方法中分配给ianywhere,那么i 必须是方法本地的新变量,而不是全局i。如果您希望 i 表示全局 i,只需在方法顶部添加以下行:

global i

【讨论】:

  • 感谢您的回复,以及有关全球和本地范围的信息。我确实知道global 关键字以及如何使此功能正常工作。我想我仍然有点不清楚为什么 Python 在不正确的行显示错误?
  • 没有错。这是引用i 的第一行。由于我们已经确定,在这个函数中,i 是一个局部变量,与全局 i 不同,因此您试图在它有值之前读取它。
  • 我明白了。所以由于它引用了i,即使它没有在该行上分配给它,它仍然被标记为异常的位置。
  • 对。分配给i 不是错误。读取不存在的i 是一个错误:准确地说是UnboundLocalError
  • “事实上,Python 语言中没有任何东西专门处理可变值(然而,这是一个常见的神话)。”是的,关于这个事实的误解的数量是惊人的。一个常见的误解是,Python 解释器在将可变对象和不可变对象作为参数传递给函数时会以某种方式区别对待。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-08
  • 1970-01-01
  • 2020-03-30
  • 2013-04-29
  • 1970-01-01
相关资源
最近更新 更多