0

I'm confused. What is different about player1_head compared to the other variables I am printing in the code below? As far as I can tell it should behave the same as the others - it's declared in the global scope, no? I don't think it's a typo.

UnboundLocalError: local variable 'player1_head' referenced before assignment

from turtle import *
from random import randint
from utils import square, vector

player1_xy = vector(-100, 0)
player1_aim = vector(4, 0)
player1_body = []
player1_head = "It looks like I'm assigning here."

def draw():
    "Advance player and draw game."
    print("xy: ", player1_xy)
    print("head: ", player1_head)
    print("body: ", player1_body)
    player1_xy.move(player1_aim)
    player1_head = player1_xy.copy()
    player1_body.append(player1_head)
    square(player1_xy.x, player1_xy.y, 3, 'red')
    update()
    ontimer(draw, 200)

setup(420, 420, 370, 0)
hideturtle()
tracer(False)

draw()
done()
DjaouadNM
  • 22,013
  • 4
  • 33
  • 55
Robin Andrews
  • 3,514
  • 11
  • 43
  • 111
  • Is this the complete code? – Iain Shelvington Aug 03 '19 at 21:04
  • Does this answer your question? [UnboundLocalError on local variable when reassigned after first use](https://stackoverflow.com/questions/370357/unboundlocalerror-on-local-variable-when-reassigned-after-first-use) – Tomerikoo Feb 10 '21 at 20:30

2 Answers2

2

Because you failed to declare player1_head as a global, in the draw() function it appears to that function that you're printing out local variable player1_head before it has a value:

print("head: ", player1_head)
# ...
player1_head = player1_xy.copy()

Instead do:

def draw():
    """ Advance player and draw game. """

    global player1_head

    print("xy: ", player1_xy)
    print("head: ", player1_head)
    print("body: ", player1_body)
    player1_xy.move(player1_aim)
    player1_head = player1_xy.copy()
    player1_body.append(player1_head)

    square(player1_xy.x, player1_xy.y, 3, 'red')

    update()
    ontimer(draw, 200)
cdlane
  • 40,441
  • 5
  • 32
  • 81
  • 1
    No "appears" about it; the presence of an assignment makes `player1_head` a local variable *throughout* the scope where the assignment takes place. Locality is not determined on a per-statement basis. – chepner Aug 03 '19 at 21:24
  • @chepner, I wasn't expressing *doubt*, I meant it appears to the `draw()` function that `player1_head` is local, not that it appears to me. I'll clarify the text. – cdlane Aug 03 '19 at 21:50
  • But why only that variable needs declaring as global inside the function, not the others? – Robin Andrews Aug 03 '19 at 22:40
  • @Robin, only that variable needs to be declared global because it is being *reset* to a new value, the other variable are only being examined or having their methods called. Read up on the Python `global` keyword -- it is often misunderstood. – cdlane Aug 04 '19 at 03:10
0

The assignment player1_head = player1_xy.copy() in the draw() function is saying to Python that the variable player1_head is a local variable to the function draw(), and since print("head: ", player1_head) is referencing a local variable before its assignment, the error is shown. You can fix this by using player1_head as a global variable (since you're modifying it, same goes for the variable player1_body, since you're doing player1_body.append(player1_head)), like so:

def draw():
    "Advance player and draw game."
    global player1_head
    #...rest of the code

Note however that you should avoid using global variables when possible, this is one the problems that arises from using them (they can be modified by any function, which can sometimes lead to errors and confusions).

DjaouadNM
  • 22,013
  • 4
  • 33
  • 55
  • So even though the print statement comes before the assignment of `player1_head` in the function, it is still treated as local even though it exists in the global scope? This seems like non-obvious behaviour to me. Something about the order in which the interpreter processes statements within a function? – Robin Andrews Aug 03 '19 at 22:44