Problem with global variables

Nick Craig-Wood nick at craig-wood.com
Fri Aug 8 22:33:20 CEST 2008


Anthony Kuhlman <kuhlmana at BATTELLE.ORG> wrote:
>  Pythoners,
>  I'm having trouble understanding the behavior of global variables in a
>  code I'm writing.  I have a file, test.py, with the following contents
> 
>  foo = []
> 
>  def goo():
>      global foo
>      foo = []
>      foo.append(2)
> 
>  def moo():
>      print foo
> 
>  In an ipython session, I see the following:
> 
>  In [1]: from test import *
> 
>  In [2]: foo
>  Out[2]: []
> 
>  In [3]: goo()
> 
>  In [4]: foo
>  Out[4]: []
> 
>  In [5]: moo()
>  [2]
> 
>  I don't understand this behavior.  I assumed that foo as defined in
>  test.py is a global object, but that doesn't seem to be the case.
>  Obviously, there's some sort of namespace thing going on here that I
>  don't get.  The ipython session seems to be dealing with one copy of foo
>  while goo() and moo() are using an entirely different copy.  
> 
>  If I take out the line 'foo = []' in goo(), everything behaves exactly
>  as I expect, that is, in ipython, when I type goo() followed by foo I
>  get [2].
> 
>  Can anyone shed some light on this behavior?

The bit of information you need to solve this problem is that python
variables are not like variables in other languages, they don't
contain values, they refer to them.  This means that there can be many
names for the same value.

You've made two variables called foo, one in the interative
interpreter (by your from "test import *" statement) and one in the
test module, and by the time you get to [4] they have different
values.  The foo in the interpreter still refers to the original list,
but the foo in the test module has been overwritten with a new list by
the assignment 'foo = []'.  This didn't affect the foo in the
interactive interpreter.

Compare and contrast with this

>>> import test
>>> test.foo
[]
>>> test.goo()
>>> test.foo
[2]
>>> test.moo()
[2]

This works as you expect because you are always using the foo from the
test namespace.

My advice is to avoid global variables completely.  Consider wrapping
all your global variables into a class and exporting a single instance
of this class to keep your globals in.

Eg
--- test2.py ---
class Test(object):
    def __init__(self):
        self.foo = []
    def goo(self):
        self.foo.append(2)
    def moo(self):
        print self.foo

test = Test()
----------------

>>> from test2 import test
>>> test.foo
[]
>>> test.goo()
>>> test.foo
[2]
>>> test.moo()
[2]
>>>   


-- 
Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick



More information about the Python-list mailing list