UnboundLocalError: variable local ‘L’ referenciada antes de la asignación Python

Cuando bash comstackr el código de abajo recibo este error

UnboundLocalError: local variable 'L' referenced before assignment 

¿Alguien puede explicar por qué? ¿No es una variable global asignada antes que nada?

Mi versión de Python es 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() 

El código mínimo para reproducir tu error es

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

Esto está sucediendo por varias razones

  1. Primero – porque en python tenemos clases mutables e inmutables. Los ints son inmutables, es decir, cuando escribes x+=1 , en realidad creas otro objeto (lo cual no es cierto para ciertos ints debido a las optimizaciones que hace CPython). Lo que realmente sucede es x = x + 1.
  2. Segundo, porque el comstackdor de Python comprueba cada asignación realizada dentro de un ámbito y hace que cada variable asignada dentro de ese scope sea local para él.
  3. Entonces, como ve cuando intenta boost x comstackdor tiene que acceder a una variable que es local para ese ámbito, pero que nunca se le asignó un valor antes.

Si está usando python2, solo tiene la opción de declarar la variable global . Pero de esta manera no podría obtener una variable de una función intermedia como

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

En python3 tienes una palabra clave nonlocal para solucionar esta situación.

También te aconsejaría que evites usar globals. También hay una collection.Counter que podría ser útil para usted.

Lectura adicional: documentos de Python

¿No es una variable global asignada antes que nada?

Sí, pero eso es completamente irrelevante. El comstackdor ve una asignación dentro de la función y marca el nombre como si estuviera en el ámbito local. Debe usar la palabra clave global al comienzo de la función para decirle al comstackdor que el nombre debe estar en el ámbito global.

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

Estás mezclando tabulaciones y espacios; no hagas eso

Ejecute su script con python -tt yourscript.py y corrija todos los errores que encuentre.

Luego configure su editor para que se adhiera solo a los espacios para la sangría; usar 4 espacios por sangría es el estilo recomendado por la Guía de estilo de Python .

A continuación, intenta boost la L global aquí:

 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 

Sin declararlo global. Agrega global L en esa función. La asignación a un nombre dentro de una función marca dicho nombre como local, a menos que específicamente le digas a Python que no lo es.