2014-01-30 2 views
5

при попытке компиляции кода ниже я получаю эту ошибкуUnboundLocalError: локальная переменная «L» обращаться до назначения Python

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() 
+3

Глобал зло – doctorlove

+1

Обратите внимания, что 'UnboundLocalError' является исключением времени выполнения, а не исключение компилятора. –

ответ

19

Минимальный код, чтобы воспроизвести вашу ошибку в

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

Это происходит по ряду причин

  1. Во-первых - потому, что в питоне есть изменяемые и неизменяемые классы. Ints неизменяемы, то есть когда вы пишете x+=1, вы фактически создаете другой объект (что неверно для определенных int из-за оптимизаций, которые делает CPython). Что на самом деле происходит, это x = x + 1.
  2. Второй - поскольку компилятор python проверяет каждое присваивание, сделанное внутри области видимости, и делает каждую переменную, назначаемую внутри этой области локальной.
  3. Итак, как вы видите, когда вы пытаетесь увеличить значение, то компилятор должен получить доступ к переменной, которая является локальной для этой области, но никогда не была назначена значение раньше.

Если вы используете python2 - у вас есть возможность объявить переменную global. Но в этом случае вы не смогло бы получить переменный из в-между функцией как

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

В Python3 у вас есть nonlocal ключевого слова для решения этой ситуации.

Также я бы посоветовал избегать использования глобальных переменных. Также есть класс collection.Counter, который может быть вам полезен.

Дальнейшее чтение: python docs

2

Вы смешиваете вкладки и пространства; не делайте этого.

Запустите свой скрипт с помощью python -tt yourscript.py и исправьте все обнаруженные ошибки.

Затем сконфигурируйте ваш редактор, чтобы он оставался только для отступов; использование 4 пробелов на отступы является рекомендуемым стилем Python Style Guide.

Далее, вы пытаетесь, чтобы увеличить глобальный 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, это не так.

+0

@Wooble: Да, вы правы; Я пропустил функцию L + = 1 в этой функции. Отступы в сообщении были ужасными, и на последующих строках были фактические вкладки с символом 'L' и' for'. –

+0

Спасибо за это. Я исправил 2 ошибки, но не решил свою проблему. – lvi

2

Isn't a global variable assigned before anything else?

Да, но это совершенно не имеет значения. Компилятор видит назначение внутри функции и помечает имя как находящееся в локальной области. Вы должны использовать ключевое слово global в начале функции, чтобы сообщить компилятору, что вместо этого имя должно быть в глобальной области.

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

Или, лучше, перепроектируйте, чтобы вообще не использовать глобальную переменную, так как это действительно ужасный дизайн. – geoffspear

Смежные вопросы