M.cudby
M.cudby

Reputation: 5

Python : Why does this work?

This is my basic randomised movement program where a cube runs down and right along going different distances each time it goes down and each time it goes right.

When writing the program i had the error message of: UnboundLocalError: local variable 'wantedcordx' referenced before assignment and UnboundLocalError: local variable 'wantedcordy' referenced before assignment

i fixed the problem by making both the variables global inside the function but have no idea why I had to do this or why it works:

Heres the program :(not very well written i'm a begginer)

import pygame,sys,random
from pygame.locals import *

#colours
red =(255,0,0)
white=(255,255,255)

#variables/objects
x = 50
y = 50
FPS = 60
clock =pygame.time.Clock()
screen = pygame.display.set_mode((800,600))
xcord = random.randint(1,100)
ycord = random.randint(1,100)

newcords_needed = False
run_once = False
def get_newcords():
    global x,y
    global run_once
    global newcords_needed
    wantedcordx
    global wantedcordy


    if run_once == False:

        xcord = random.randint(1, 100)
        ycord = random.randint(1, 100)
        wantedcordy = (y + ycord)
        wantedcordx = (x + xcord)
        run_once = True
        print(wantedcordx)

    if newcords_needed == True:
        xcord = random.randint(1,100)
        ycord = random.randint(1,100)
        wantedcordy = (y + ycord)
        wantedcordx = (x + xcord)
        newcords_needed = False

    if x != wantedcordx:
        x_done = False
        x +=1


    elif x == wantedcordx:
        x_done = True

    if x_done == True:
        if y  != wantedcordy:
        y +=1
        elif y == wantedcordy:
            y_done = True
            newcords_needed = True
    return (x,y)





while True:
    clock.tick(FPS)
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
    get_newcords()
    screen.fill(white)
    pygame.draw.rect(screen, red, [x,y,20,20])
    pygame.display.update()

It never copys and pastes in correctly but I did my best to reformat it.

Upvotes: 0

Views: 72

Answers (2)

xioustic
xioustic

Reputation: 56

Check out the official programming documentation FAQ for Python, specifically the section about "Why am I getting an UnboundLocalError when the variable has a value?": https://docs.python.org/2/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value

The question immediately after deals with why and where "global" is needed, which may also be helpful to you.

In short, it's a choice in the Python language to allow access to global definitions "implicitly" (meaning it's a safe assumption in most cases), but the ability to change them requires the explicit use of the "global" keyword. The limitation is to remind you that you are modifying something that may be shared (ie global) which may introduce unintended side-effects in other sections of your code if you are not mindful. The only reason that they did not require "global" for accessing the value as well is because the resulting "clutter would defeat the usefulness of the global declaration for identifying side-effects."

It should be noted that utilizing globals in many scenarios is considered bad practice, not just in Python, and that the ideal solution in Python is typically utilizing the namespacing system offered by modules. This is further detailed in the FAQ section I linked you. However, when developing a simple game, it is often useful (practical?) to have a set of globals as the "one true source of truth" at any given moment represent the state of the world accessible to most portions of code.

Upvotes: 1

Jean-François Fabre
Jean-François Fabre

Reputation: 140256

in def get_newcords(), if run_once == True and newcords_needed == False, the first time variable wantedcordx is accessed is here:

if x != wantedcordx:

since the first time it's accessed in that case is through a read access, you get "undefined variable", unless you define it global like you did.

(same goes for wantedcordy)

Defining them global has the following effect: since at first call of the function, you assign wantedcordx to something, it remains valid in the next function calls.

Upvotes: 1

Related Questions