tags:

views:

106

answers:

3

I have a global variable I called Y_VAL which is initialized to a value of 2.

I then have a function, called f() (for brevity), which uses Y_VAL.

def f():
    y = Y_VAL
    Y_VAL += 2

However, when trying to run my code, python gives the error message:

UnboundLocalError: local variable 'Y_VAL' referenced before assignment

If I remove the last line Y_VAL += 2 it works fine.

Why does python think that Y_VAL is a local variable?

+11  A: 

You're missing the line global Y_VAL inside the function.

When Y_VAL occurs on the right-hand-side of an assignment, it's no problem because the local scope is searched first, then the global scope is searched. However, on the left-hand-side, you can only assign to a global that way when you've explicitly declared global Y_VAL.

From the docs:

It would be impossible to assign to a global variable without global, although free variables may refer to globals without being declared global.

Mark Rushakoff
Does this behavior apply differently for dicts? I found that I can declare a global dict and then assign to it inside a function without using `global`... might you know the reasoning behind this?
VMDX
Hmmm, it seems like I have the same question as VMDX. Given a global dictionary 'd', I have been able to add/change it without using the keyword global. How come this is the case? same with lists
Paul
You can change the contents *inside* the list or dict. You can't change (rebind) the reference to the list/dict. So `d[2:]= 3` is OK, but `d+= [3]` is not.
bobince
The difference has nothing to do with dicts at all. You are simply comparing two completely different operations: "Assignment to a name" and "assignment to an item of an object bound to a name".`foo[i] = bar` performs a name lookup for `foo` in local and global namespace (in this order), and then sets the item at index `i` to `bar` (by invoking `foo.__setitem__()`). `foo = bar` does not perform any lookup at all, but simply sets the name `foo` in the local namespace (unless `foo` as been declared global or nonlocal).
lunaryorn
+1  A: 

This is just how Python works: Assignment always binds the left-hand side name in the closest surrounding name space. Inside of a function the closest namespace is the local namespace of the function.

In order to assign to a global variable, you have to declare it global. But avoid global by all means. Global variables are almost always bad design, and thus the use of the global keyword is a strong hint, that you are making design mistakes.

lunaryorn
A: 

I ran to the same issue as you and as many others like you, before realising it needs the global statement. I then decided to move everything to object orientation and have piece of mind. Call me insane but I just dont trust myself with the global statement and its not difficult to come against a problem of local scope that is a pain to debug.

So I would advice collect all your "global" variables put them in a class inside an init(self) and not only you wont have to worry about local scope but you will have your code much better organised. Its not a freak of luck that most programmer out there prefer OOP.

Kilon