UnboundLocalError: 在赋值之前引用了本地变量'L',Python

12

尝试编译下面的代码时,我遇到了这个错误

UnboundLocalError: local variable 'L' referenced before assignment

有人能解释一下为什么吗?全局变量不是在任何其他东西之前就被分配了吗?

我的Python版本是2.7.3

#!/usr/bin/env python

import pygame
from pygame.locals import *
from sys import exit
import random
import math

R = int(8)  # promien planety
N = 5  # liczba planet
G = 2  # stala "grawitacyjna"
L = 1

def compute_dv(p1,p2):
    dx = p2[0]-p1[0]
    dy = p2[1]-p1[1]
    r = math.hypot(dx,dy)
    dx /= r*r
    dy /= r*r
    if(L>1000):
   print "r= ", r, "dx= ", dx, "dy= ", dy, "dx/ r*r = ", dx, "dy/ r*r = ", dy
    L+=1
    return G*dx,G*dy


def rand_color():
    r = 32*random.randint(0,7)
    g = 32*random.randint(0,7)
    b = 22*random.randint(0,7)
    return (r,g,b)


pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)

points = []
vs = []
colors = []

for i in range(N):
    points.append( [random.randint(0,639), random.randint(0,480)] )
    vs.append( [0,0] )
    colors.append( rand_color() )

clock = pygame.time.Clock()

screen.fill( (255,255,255))

while True:
    clock.tick(30)

for event in pygame.event.get():
    if event.type == QUIT:
        exit()

for i in range(len(points)):
   for j in range(len(points)):
      if points[i]!=points[j]:
         dvx,dvy = compute_dv( points[i],points[j])
         vs[i][0] += dvx
         vs[i][1] += dvy

for i in range(len(points)):
    points[i][0] += vs[i][0]
    points[i][1] += vs[i][1]

screen.fill( (255,255,255))

for i in range(len(points)):
  L = []
  for w in points[i]:
print int(round(w))
L.append(int(round(w)))
  points[i] = L
  print points[i], "stop"
  #x = raw_input()

  pygame.draw.circle(screen, colors[i], points[i], R)  

pygame.display.update()  

1
请注意,UnboundLocalError 是运行时异常,而不是编译器异常。 - Martijn Pieters
3个回答

28

重现错误的最简代码如下:

x = 1
def foo():
    x += 1
foo()

这是由于多种原因导致的。

  1. 首先,因为在Python中我们有可变和不可变的类。整数是不可变的,也就是说当你写 x+=1 时,实际上会创建另一个对象(对于某些整数由于CPython的优化不是这样)。实际发生的是 x = x + 1。
  2. 其次,因为Python编译器检查作用域内进行的每个赋值,并使该作用域内分配的每个变量都成为局部变量。
  3. 因此,当您尝试增加 x 时,编译器必须访问该作用域内的一个从未被赋值过的变量。

如果您使用的是Python2,则只能选择声明全局变量。但是这样做将无法从中间函数获取变量,例如

x = 0
def foo():
  x = 1
  def bar():
    global x
    print x  # prints 0
  bar()
foo()    

在Python3中,您可以使用nonlocal关键字来解决这种情况。

此外,我建议您避免使用全局变量。此外,collections.Counter类可能对您有用。

进一步阅读:Python文档


3

全局变量不是在其他任何东西之前被分配的吗?

是的,但这完全不相关。编译器看到函数内的分配并将名称标记为处于本地作用域。您需要在函数开头使用global关键字告诉编译器该名称应该在全局范围内。

def compute_dv(p1,p2):
    global L
     ...

或者,更好的方式是重新设计,根本不使用全局变量,因为这是一个非常糟糕的设计。 - Wooble

2
你混用了制表符和空格,请不要这样做。
使用python -tt yourscript.py运行你的脚本,并修复它发现的所有错误。
然后配置你的编辑器只使用空格缩进;每个缩进使用4个空格是Python风格指南推荐的风格。
接下来,你在这里尝试增加全局变量L
def compute_dv(p1,p2):
    # ...

    if(L>1000):
        print "r= ", r, "dx= ", dx, "dy= ", dy, "dx/ r*r = ", dx, "dy/ r*r = ", dy
        L+=1

在不将其声明为全局变量的情况下。在该函数中添加 global L。在函数内部对名称进行赋值会将该名称标记为局部变量,除非你明确告诉 Python 它不是。

@Wooble:是的,你说得对;我在函数中错过了 L+=1。帖子中的缩进很糟糕,在后面几行中有实际的制表符、L 和一个 for 循环。 - Martijn Pieters
谢谢您的回复。我已经修正了两个错误,但是还没有解决我的问题。 - lvi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接