What's wrong with this code? (UnboundLocalError: local variable referenced before assignment)

Dave Angel davea at davea.name
Mon Jun 24 16:43:15 EDT 2013


On 06/24/2013 04:12 PM, John Gordon wrote:
> In <b3d3518a-f24a-4c32-a41a-b99145753528 at googlegroups.com> pablobarhamalzas at gmail.com writes:
>
>> isWhite = True
>>
>> def change(event):
>>      if event.x > x1 and event.x < x2 and event.y > y1 and event.y < y2:
>>          if isWhite:
>>              w.itemconfig(rect, fill="blue")
>>              isWhite = False
>>          else:
>>              w.itemconfig(rect, fill="white")
>>              isWhite = True
>>
>> w.bind("<Button-1>", change)
>>
>> root.mainloop()
>
>> The problem occurs when clicking on the white square. The following error
>> appears:
>> "if isWhite:
>> UnboundLocalError: local variable 'isWhite' referenced before assignment"
>
>> However, the isWhite variable is clearly defined at "True" a few lines
>> before.
>
> Since you're new to programming, this might be a bit tricky to explain,
> but I'll do my best. :-)
>
> The problem is that change() isn't being executed here; instead it's being
> executed from within root.mainloop(), whenever the user presses button-1.
>
> And within root.mainloop(), there is no variable called isWhite.
>

Actually that's irrelevant.  Whether or not there's one global with the 
same name, or twenty-three object attributes with the same name, the 
fact that there's a binding of the local makes that name a local.  The 
only way to avoid that is not to bind, or to use global or nonlocal 
declarations.


Pablo:  Global variables are generally frowned upon, unless they're 
constant.  If they're constant, use ALLCAPS to indicate that.  Since 
this is not, it would normally be an attribute of some object, in your 
case, possibly the object w.  And of course, w should have been an 
argument to the function as well, since you're operating on it.  But you 
may be stuck with that, because of tkinter's design.  Anyway, you can assign
     w.isWhite = True

and access
     if w.isWhite

with impunity, since w is not being bound inside the function.


When you need to pass extra arguments that the event model doesn't allow 
for, one approach is to use functools.partial().

And it's also possible that there's a method (in tkinter) on event that 
let's you find the object that it's acting upon, w.  In this case, you 
could avoid needing a global at all, which would be a big improvement. 
Especially when you decide to have multiple such boxes, and want each to 
be able to toggle colors independently.


-- 
DaveA



More information about the Python-list mailing list