Notes on Python variable scope



This is my OLD blog. I've copied this post over to my NEW blog at:

http://www.saltycrane.com/blog/2008/01/python-variable-scope-notes/

You should be redirected in 2 seconds.



Example 1: The difference between global and local variables
Global variables are accessible inside and outside of functions. Local variables are only accessible inside the function. In the example below, the function can access both the global and the local variable. However, trying to access the local variable outside the function produces an error.

global_var = 'foo'
def ex1():
    local_var = 'bar'
    print global_var
    print local_var

ex1()
print global_var
print local_var  # this gives an error
foo
bar
foo
Traceback (most recent call last):
  File "nested_scope.py", line 12, in 
    print local_var  # this gives an error
NameError: name 'local_var' is not defined

Example 2: How *not* to set a global variable
*Setting* a global variable from within a function is not as simple. If I set a variable in a function with the same name as a global variable, I am actually creating a new local variable. In the example below, var remains 'foo' even after the function is called.

var = 'foo'
def ex2():
    var = 'bar'
    print 'inside the function var is ', var

ex2()
print 'outside the function var is ', var
inside the function var is  bar
outside the function var is  foo

Example 3: How to set a global variable
To set the global variable inside a function, I need to use the global statement. This declares the inner variable to have module scope. Now var remains 'bar' after the function is called.

var = 'foo'
def ex3():
    global var
    var = 'bar'
    print 'inside the function var is ', var

ex3()
print 'outside the function var is ', var
inside the function var is  bar
outside the function var is  bar

Example 4: Nested functions
Scoping for nested functions works similarly. In the example below, the inner function can access both var_outer and var_inner. However, the outer function cannot access var_inner. Side note: the inner function is considered a closure if it makes reference to a non-global outside variable.

def ex4():
    var_outer = 'foo'
    def inner():
        var_inner = 'bar'
        print var_outer
        print var_inner
    inner()
    print var_outer
    print var_inner # this gives an error

ex4()
foo
bar
foo
Traceback (most recent call last):
  File "nested_scope.py", line 53, in 
    ex3()
  File "nested_scope.py", line 51, in ex3
    print var_inner # this gives an error
NameError: global name 'var_inner' is not defined

Example 5: How *not* to set an outer variable
Like Example 2, setting a variable in the inner function creates a new local variable instead of modifying the outer variable. In the example below, var in the outer function does not get changed to 'bar'.

def ex5():
    var = 'foo'
    def inner():
        var = 'bar'
        print 'inside inner, var is ', var
    inner()
    print 'inside outer function, var is ', var

ex5()
inside inner, var is  bar
inside outer function, var is  foo

Example 6: Another way to *not* set an outer variable
However, using the global keyword won't work in this case. global cause a variable to have module scope, but I want my variable to have the scope of the outer function. Per the Python 3000 Status Update, Python 3000 will have a nonlocal keyword to solve this problem. See PEP 3104 for more information about nonlocal and nested scopes. In the example below, var is still not changed to 'bar' in the outer function.

def ex6():
    var = 'foo'
    def inner():
        global var
        var = 'bar'
        print 'inside inner, var is ', var
    inner()
    print 'inside outer function, var is ', var

ex6()
inside inner, var is  bar
inside outer function, var is  foo

Example 7: A workaround until Python 3000 arrives
A workaround is to create an additional namespace. Now the variable in the outer function can be set to 'bar'.

class Namespace: pass
def ex7():
    ns = Namespace()
    ns.var = 'foo'
    def inner():
        ns.var = 'bar'
        print 'inside inner, ns.var is ', ns.var
    inner()
    print 'inside outer function, ns.var is ', ns.var
ex7()
inside inner, ns.var is  bar
inside outer function, ns.var is  bar

Reference: Core Python Programming, Second Edition, Ch 11

4 comments:

Anonymous said...

Many thanks for this post! I could not find the solution to setting global variables anywhere in all my python documentation.

Anonymous said...

Another workaround is to wrap the variable in a mutable:
>>> def ex8():
... var = ['foo']
... def inner():
... var[0] = 'bar'
... print 'inside inner, var is ', var
... inner()
... print 'inside outer function, var is ', var
...
>>> ex8()
inside inner, var is ['bar']
inside outer function, var is ['bar']
>>>

Unknown said...

Can anybody tell me what's wrong in the below code:

argref_list = []
for entry in arg_l: # processing #nnnn($Fmm)
print argref_list
argref_list.append(decode_single_argument(entry.strip()))


the output is:
[]
NONE

note that 'NONE' is printed (strange) and secondly throws the error that NONETYPE has no append function.

I am fade up with PYTHON!

Please help!

Anonymous said...

Nice post, told me exactly what I needed to know!

About

This is my *OLD* blog. I've copied all of my posts and comments over to my NEW blog at:

http://www.saltycrane.com/blog/.

Please go there for my updated posts. I will leave this blog up for a short time, but eventually plan to delete it. Thanks for reading.