please help explain this result

Y

Yingjie Lan

Hi,

I played with an example related to namespaces/scoping.
The result is a little confusing:
a = a + 1
return a

I suppose I will get 2 ( 'a' is redefined as a local variable, whose value is obtained by the value of the global variable 'a' plus 1). But this is what I got:
a = a + 1
return a
Traceback (most recent call last):
File "<pyshell#39>", line 1, in <module>
f()
File "<pyshell#38>", line 2, in f
a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment


I'm not sure how to explain this? Thanks!

Yingjie
 
N

Nobody

I played with an example related to namespaces/scoping. The result is a
little confusing:
a = a + 1
return a
UnboundLocalError: local variable 'a' referenced before assignment

If you want to modify a global variable, you have to explicitly declare it
as global. In this case, you need to add "global a" at the top of the
function.

If a function assigns to a name which isn't explicitly declared global, it
is treated as a local variable. If you reference it before the first
assignment, you get the above error.

If the function doesn't assign to it, or if it's explicitly declared
global, it is treated as global variable.

The determination of local or global is made when the "def" statement is
executed, not when the function is called.
 
S

Steven D'Aprano

Hi,

I played with an example related to namespaces/scoping. The result is a
little confusing:

[snip example of UnboundLocalError]

Python's scoping rules are such that if you assign to a variable inside a
function, it is treated as a local. In your function, you do this:

def f():
a = a + 1

Since a is treated as a local, when you enter the function the local a is
unbound -- it does not have a value. So the right hand side fails, since
local a does not exist, and you get an UnboundLocalError. You are trying
to get the value of local "a" when it doesn't have a value.

Why doesn't Python treat the "a" on the right-hand side as global, and
"a" on the left-hand side as local? That would be confusing, if variables
had different scope in different places. Python's current scoping rules
are simple:

(1) If you assign to a variable *anywhere* in the function, it is a local
*everywhere* in the function.

(2) If you refer to a variable (without assigning to it) in the function,
and it is not a local, Python searches the nested scopes for a matching
name. This is necessary so that globals and built-ins will be found, but
it also works for nested functions and closures. E.g.

def f(alist):
n = len(alist)

Obviously alist and n are local variables, but what you might not realise
is that len() is not known to the compiler, it is just the name of a
variable which is looked up at runtime.

(3) If you flag a variable with the global statement, then it will be
treated as global for assignments.

There is no way to have a variable refer to a local in some places of a
function and a global in other places of the same function. This is by
design.


[...]
I suppose I will get 2 ( 'a' is redefined as a local variable, whose
value is obtained by the value of the global variable 'a' plus 1).

No, Python does not do that.
 
P

Paul Kölle

Am 17.10.2010 13:48, schrieb Steven D'Aprano:
Hi,

I played with an example related to namespaces/scoping. The result is a
little confusing:

[snip example of UnboundLocalError]

Python's scoping rules are such that if you assign to a variable inside a
function, it is treated as a local. In your function, you do this:

def f():
a = a + 1

Since a is treated as a local, when you enter the function the local a is
unbound -- it does not have a value. So the right hand side fails, since
local a does not exist, and you get an UnboundLocalError. You are trying
to get the value of local "a" when it doesn't have a value.
Oh really? Can you explain the following?
.... a['a'] = 'lowercase a'
.... print a.keys()
....
>>> foo() ['a']
>>> a {'a': 'lowercase a'}
>>> def bar():
.... a['b'] = a['a'].replace('a', 'b')
....
cheers
Paul
 
T

TomF

Am 17.10.2010 13:48, schrieb Steven D'Aprano:
Hi,

I played with an example related to namespaces/scoping. The result is a
little confusing:

[snip example of UnboundLocalError]

Python's scoping rules are such that if you assign to a variable inside a
function, it is treated as a local. In your function, you do this:

def f():
a = a + 1

Since a is treated as a local, when you enter the function the local a is
unbound -- it does not have a value. So the right hand side fails, since
local a does not exist, and you get an UnboundLocalError. You are trying
to get the value of local "a" when it doesn't have a value.

Steven's explanation is correct. In your example below you're altering
portions of a global data structure, not reassigning a global variable.
Put another way, there is a significant difference between:
a = 7
and:
a['x'] = 7

Only the first reassigns a global variable.

-Tom
Oh really? Can you explain the following?
... a['a'] = 'lowercase a'
... print a.keys()
...
foo() ['a']
a {'a': 'lowercase a'}
def bar():
... a['b'] = a['a'].replace('a', 'b')
...
cheers
Paul
 
D

Dennis Lee Bieber

Oh really? Can you explain the following?
... a['a'] = 'lowercase a'
... print a.keys()
...
foo() ['a']
a {'a': 'lowercase a'}
def bar():
... a['b'] = a['a'].replace('a', 'b')
...
You never rebound a value to a itself... All usage of a within the
functions are as mutable containers and you are rebinding components
within the container.

As soon as you use a [ or . after a name, you signal that your
intention is to access something held within the object the name is
bound to, but not the object itself. Since you are not rebinding the
name to a different object, the compiler leaves it as a global name.
 
P

Paul Kölle

Am 17.10.2010 19:51, schrieb TomF:
Am 17.10.2010 13:48, schrieb Steven D'Aprano:
On Sun, 17 Oct 2010 03:58:21 -0700, Yingjie Lan wrote:

Hi,

I played with an example related to namespaces/scoping. The result is a
little confusing:

[snip example of UnboundLocalError]

Python's scoping rules are such that if you assign to a variable
inside a
function, it is treated as a local. In your function, you do this:

def f():
a = a + 1

Since a is treated as a local, when you enter the function the local
a is
unbound -- it does not have a value. So the right hand side fails, since
local a does not exist, and you get an UnboundLocalError. You are trying
to get the value of local "a" when it doesn't have a value.

Steven's explanation is correct. In your example below you're altering
portions of a global data structure, not reassigning a global variable.
Put another way, there is a significant difference between:
a = 7
and:
a['x'] = 7

Only the first reassigns a global variable.

Thanks Tom and Dennis.

This will teach me (hopefully) to pay attention to details next time and
I think I learned something too. I always thought the rules about
changing "global" objects where inconsistent because it works for
mutables... Turns out it's all fine since assignment doesn't work for
mutables too and assignment just happens to be the only way to "change"
immutables ;)

cheers
Paul
-Tom
Oh really? Can you explain the following?
a = {}
def foo():
... a['a'] = 'lowercase a'
... print a.keys()
...
foo() ['a']
a {'a': 'lowercase a'}
def bar():
... a['b'] = a['a'].replace('a', 'b')
...
{'a': 'lowercase a', 'b': 'lowercbse b'}
cheers
Paul
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top