【问题标题】:Local Variable Referenced before Assignment - Python赋值前引用的局部变量 - Python
【发布时间】:2021-04-15 05:39:05
【问题描述】:
x = 2
y = 3

mylist = [ [x,y] for x in range(x+1) for y in range(y+1)]

print(mylist) 

UnboundLocalError Traceback(最近调用 最后)在 3 4 ----> 5 mylist = [ [x,y] for x in range(x+1) for y in range(y+1)] 6 7 打印(我的列表)

在 (.0) 3 4 ----> 5 mylist = [ [x,y] for x in range(x+1) for y in range(y+1)] 6 7 打印(我的列表)

UnboundLocalError: 在赋值之前引用了局部变量 'y'

我不明白这里出了什么问题以及如何纠正它。

【问题讨论】:

  • 万一您在下面的正确答案中看不到它,问题是您将变量 xy 用于两个相互冲突的目的:循环输入和循环变量。 Python 无法理顺它们。
  • 这是一个关于作用域如何用于理解的有趣示例

标签: python python-3.x list list-comprehension


【解决方案1】:

这是因为多级推导中的内部推导的 CPython 实现是使其成为一个单独的函数,它有自己的范围。通过将y 设为左值并将其用作迭代变量,Python 编译器将y 确定为单独函数的局部变量,因此range(y+1) 中的y 不能引用是因为本地 y 尚未在该函数范围内分配值。

您可以在理解中重命名本地 y

mylist = [[x, z] for x in range(x + 1) for z in range(y + 1)]

或者改用非理解的解决方案:

mylist = []
for x in range(x + 1):
    for y in range(y + 1):
        mylist.append([x, y])

【讨论】:

  • 仅重命名本地 y 并不能完全解决问题。 OP 必须同时更改本地 xy
  • 您的非理解解决方案产生的结果与预期的不同。
  • 谢谢。我已经用更正的解释和解决方案更新了我的答案。 x 不需要重命名,因为它是在理解的最外层赋值的,CPython 的实现不会变成函数。
  • ? 也感谢您对x 的解释!这很有趣,不知道。
  • 小细节:您的非理解解决方案仍会产生略有不同的结果。元素正确,但顺序不正确。
【解决方案2】:

通常,当您调用一个在分配给它之前引用本地范围内的名称的函数时,您会看到此错误。碰巧的是,列表推导中的最外层范围在 Python 3 中的工作方式相同。这是对 Python 2 的一个更改,其中推导中的循环变量会污染外部命名空间。

在这种特殊情况下,使用xy 作为循环变量会告诉解释器这些是局部变量。但是,range(x + 1)range(y + 1) 会在分配这些变量之前尝试读取它们。 Python 有一个优化,可以从一个特殊的表中读取被确定为函数(或理解)命名空间的本地变量,而不是使用正常的 LEGB 查找顺序。这就是为什么你得到错误而不是使用外部范围的值。

此过程的副作用是 xy 的最后一个值不会更改您在外部范围中分配的值。

要解决此问题,请确保定义范围的变量与循环变量的名称不同。

【讨论】:

    【解决方案3】:

    试试这个:

    x = 2
    y = 3
    
    mylist = [[j,k] for j in range(x+1) for k in range(y+1)]
    
    print(mylist)
    

    打印出来:

    [[0, 0], [0, 1], [0, 2], [0, 3], [1, 0], [1, 1], [1, 2], [1, 3], [2, 0], [2, 1], [2, 2], [2, 3]]
    

    正如@Tim Roberts 在他的评论中指出的那样,您在列表理解中使用了xy «用于两个相互冲突的目的»。您需要在 for 循环中为它们中的每一个赋予唯一的名称,例如y -> k.

    进一步查看 at this SO post 以了解有关嵌套列表推导的更多信息。

    【讨论】:

    • “在列表理解中使用 xy 两次”不是错误的原因。
    • 你是对的,我的错。我的语言不准确。根据@Tim Roberts 的评论修正了解释。
    猜你喜欢
    • 2021-03-13
    • 1970-01-01
    • 1970-01-01
    • 2015-06-14
    • 2018-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    相关资源
    最近更新 更多