代码之家  ›  专栏  ›  技术社区  ›  Jean-François Fabre

为什么在平面图的第二个变量上会出现UnboundLocalError?

  •  8
  • Jean-François Fabre  · 技术社区  · 6 年前

    我在这里回答了一个问题: comprehension list in python2 works fine but i get an error in python3

    OP的错误是对最大范围和指数使用相同的变量:

    x = 12
    y = 10
    z = 12
    n = 100
    
    ret_list = [ (x,y,z) for x in range(x+1) for y in range(y+1) for z in range(z+1) if x+y+z!=n ]
    

    这只是一个Python-3错误,与添加到理解中的作用域有关,以避免此处定义的变量“泄漏”。更改变量名可以解决这个问题。

    错误是:

    UnboundLocalError: local variable 'y' referenced before assignment
    

    因为外部的,全球性的 y 被局部作用域遮蔽。

    y 而不是开着 z x ?

    编辑:如果我删除 ,错误移到 z :

    >> ret_list = [ (x,y,z) for y in range(y+1) for z in range(z+1) if x+y+z!=n ]
    UnboundLocalError: local variable 'z' referenced before assignment
    

    如果我只做一个循环:

    ret_list = [ (x,y,z) for y in range(y+1) if x+y+z!=n ]
    

    它起作用了。所以我怀疑 range 函数被求值 之前 所有其他表达式,这会留下

    1 回复  |  直到 6 年前
        1
  •  6
  •   Community pid    4 年前

    reference documentation (我的)。

    for 子句中,理解在单独的隐式嵌套范围中执行。这样可以确保在目标列表中分配给的名称不会泄漏到封闭范围中。

    对于 后续 对于 子句和最左边的任何筛选条件 子句不能在封闭范围中求值,因为它们可能依赖于从最左边的iterable中获得的值。例如: [x*y for x in range(10) for y in range(x, x+10)] .

    这意味着:

    list_ = [(x, y) for x in range(x) for y in range(y)]
    

    相当于:

    def f(iter_):
        for x in iter_:
            for y in range(y):
                yield x, y
    
    list_ = list(f(iter(range(x))))
    

    x . 但对我来说,情况并非如此 y ,这就是为什么 UnboundLocalError

    list(<generator expression>) ,因此它将使用与生成器表达式相同的代码路径(或者至少以相同的方式运行)。生成器表达式计算最左侧的iterable表达式 对于

    y = None                             # line 1
    gen = (x + 1 for x in range(y + 1))  # line 2
    item = next(gen)                     # line 3
    

    y 显然是错误的类型,因此添加将提高 TypeError range(y + 1) 立即在第2行而不是第3行出现类型错误。因此,更容易诊断问题发生的位置和原因。如果它发生在第3行,那么你可能会错误地认为它是 x + 1 导致错误的语句。

    here 提到了这种行为。它被解析为“不是一个bug”,因为列表理解和生成器表达式具有相同的行为是可取的。