[Tutor] Scoping question

Gonçalo Rodrigues op73418@mail.telepac.pt
Mon, 9 Sep 2002 18:00:48 +0100


----- Original Message -----
From: "Dana Larose" <dana@pixelenvy.ca>
To: <tutor@python.org>
Sent: Monday, September 09, 2002 4:27 PM
Subject: [Tutor] Scoping question


> Hello,

Hello

>
> (Hope this is the right mailing list for this question!)
>

It is.

> I've been using Python for several months now, and I've run across a
> scoping issue involving global variables.  Consider this program scrap:
>
> blah = 0
> list = [0]
>
> def foo():
> blah += 1
>
> def bar():
> list[0] += 1
>
> Now, bar would compile and execute fine, but foo is illegal because:
>
> 'UnboundLocalError: local variable 'blah' referenced before assignment'
>
> Now, I'll guess that my problem is that Python is treating blah as though
> it were local and the assignment fails because the variable hasn't been
> created yet.  But why doesn't Python search up the scoping chain when the
> local assignment fails?  Also, if foo had been defined as just being:
>
> def foo():
> print blah
>
> It executes just fine and can find blah.  Why can it find the global in
> this context but not the other?
>
> And finally, why does the assignment to a list element execute
> successfully?
>
> Dana.
> dana@pixelenvy.ca
>

The problem is the difference between local variables and global ones.

Consider the scrap

>>> blah = 1
>>> def foo():
...  print blah
...
>>> foo()
1

Here Python knows that I wanted to acess the global blah because blah is a
free name inside foo (i.e. there is no assignment to it). Now consider

>>> def foo2():
...  blah = 2
...  print blah
...
>>> foo2()
2
>>> print blah
1

Here Python has created a *local* blah inside foo, which, when foo is done,
is discarded - and that is why print blah gives the global blah, e.g. 1. Now
consider

>>> def foo3():
...  blah += 1
...
>>> foo3()
Traceback (most recent call last):
  File "<interactive input>", line 1, in ?
  File "<interactive input>", line 2, in foo3
UnboundLocalError: local variable 'blah' referenced before assignment

According to the first case, the name blah is local and you are rebinding
it. But blah += 1 is a shortcut for

blah = blah + 1

so you are trying to acess something that it is not defined.

*IF* you want to acess the global blah inside foo you have to explicitly
order Python to do so, e.g.

>>> def foo4():
...  global blah
...  blah += 1
...
>>> foo4()
>>> print blah
2

Hope it helps,
Gonçalo Rodrigues