[Tutor] Global var problem

Andrei project5 at redrival.net
Sat Oct 29 00:14:46 CEST 2005


Hi Nick,

> messing about with classes I've come across something basic that I don't 
> understand.

Your issue is not so much with classes as it is with namespaces. You'll 
hit the exact same problem with simple functions.

> Take this class
> 
> class T:
>         def p(self):
>                 print x

In this case, the Python reference states that if a name (x) is not 
found in a block (i.e. inside the p method), it will look in its 
surrounding scope for it. That would be the global namespace. Given the 
fact that you defined x as a global variable, it finds it there and it 
works as expected.

> Now this
> class T:
>         def p(self):
>                 x += 1
>                 print x
> This outputs
> UnboundLocalError: local variable 'x' referenced before assignment

Here is what the Python docs have to say about assignment:

   If the target is an identifier (name):
     If the name does not occur in a global statement in the current code
     block: the name is bound to the object in the current local
     namespace.

In other words, when trying to assign a new value to x, it:
1. looks if x was defined as global *inside the current function/class*
2. sees that it was not defined as global -> therefore it must be local
3. tries to get the value of that local x
4. finds there is no local x -> raises exception

> So I tried this
> 
> class T:
>         def p(self):
>                 x += 1
>                 print x
> 
> if __name__ == '__main__':
>         global x
>         x = 1
>         t = T()
>         t.p()
> but that gives me the same UnboundLocalError exception.

This second attempt is almost but not quite right: the global statement 
is in the wrong place. x is by definition global if defined outside a 
class or function, so adding "global" in front of it won't make a 
difference. The point is that if you try to assign a value to a global 
variable inside a function or class definition, you must tell Python *in 
that block* that you want to assign to a global variable, not a local one.

 >>> def p():
...     global x
...     x += 1
 >>> x = 5
 >>> p()
 >>> x
6

Similar problems can occur when defining a function inside another function:

 >>> def a():
...     aa = 2
...     def b():
...         print aa # aa in surrounding namespace, not local to b()
...     b()
 >>> a()
2
 >>> def a():
...     aa = 2
...     def b():
...         aa += 1 # in surrounding namespace, not local to b()
...         print aa
...     b()
 >>> a()
UnboundLocalError: local variable 'aa' referenced before assignment


> No doubt the answer is staring me in the face ... but I still can't see it.

I would recommend against using global variables this way (modifying 
them inside functions). It's better to use method parameters for input 
and the return statement to output any necessary modifications, e.g.:

def p(inp):
     output = inp + 1
     print output
     return output

if __name__ == '__main__':
     x = 5
     x = p(x)

It would be even better with a decent function name of course :). More 
info available in paragraph 4.1 of the Python reference manual.

-- 
Yours,

Andrei

=====
Mail address in header catches spam. Real contact info:
''.join([''.join(s) for s in zip(
"poet at aao.l pmfe!Pes ontuei ulcpss  edtels,s hr' one oC.",
"rjc5wndon.Sa-re laed o s npbi ot.Ira h it oteesn edt C")])



More information about the Tutor mailing list