赋值前引用的局部变量 - Python

问题描述

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'

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

解决方法

这是因为多级推导中内部推导的CPython实现是使其成为一个单独的函数,有自己的作用域。通过将 y 用作迭代变量的左值,y 被 Python 编译器确定为单独函数的局部变量,因此 y 在无法引用 range(y+1),因为本地 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])
,

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

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

此过程的副作用是 range(y + 1)x 的最后一个值不会更改您在外部作用域中分配的值。

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

,

试试这个:

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],2],3],[1,[2,3]]

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

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...