Carrying variables over from function to function

Magnus Lycka lycka at carmen.se
Tue Sep 27 13:39:30 EDT 2005


Ivan Shevanski wrote:
> Thanks for your quick responce Roy, thats exactly what I needed. =)

No, it isn't! ;)

It might seem like a good idea right now, but it's not
a good choice in the long run. It's like peeing in bed:
Initially it's both a relief and you get warm and cosy,
but you'll end upp with a mess that you (or someone else)
will need to clean up later.

Sure, it's unproblematic in this tiny example, but it's
a bad habit to rely on global variables in cases that
are easily solved without them. The obvious solution in
your case is to just pass on the variable you need.

There are several problems with globals that will become
appearent as your code grows bigger, and you can't see
all details in the program in the same instant. Your
global namespace will get cluttered by a lot of names that
are used far away in the code, the code in your functions
will become difficult to understand, and it will be more
difficult to see how the functions interact to each other.
Your programs will also be brittle, since a change in one
place is more likely to break some other code in another
place in your program. Besides, if your code relies on
changing global variables, your functions get very
restricted: You can't have two or more sets of data
being modified by these functions at the same time.

It's pretty common in Python, that people use global
variables for objects that are really constants (although
Python won't enforce that) and it's common that these
varaible names are written with CAPS. There are also
cases where we want to keep some kind of module global
state, and globals can be used for that, but it should
be used only when needed. I just scanned through 55 000
lines of Python code in 276 files here at work, and found
about a dozen occurences of the global keyword.

In other words, it's very uncommon here that we use
global variables that aren't just constants.

The normal way to share data between functions is to
pass data in as arguments, and out as return values.

If you want objects to keep state between function
calls without passing them around, consider using
object-oriented code, but lets wait a bit with that.
Anyway, here are two examples of a small program
using globals or passing parameters.

# Global version

def getYear():
     global year
     year = None
     while year is None:
         try:
             year = int(raw_input(prompt))
         except ValueError:
             pass

def calcAge():
     global age
     age = current_year - birth_year

def printAge():
     print "*"*age
     print "You are", age, "years."


def main():
     global prompt
     prompt = 'What year were you born? '
     getYear()
     global birth_year
     birth_year = year
     prompt = 'What year is it now? '
     getYear()
     global current_year
     current_year = year
     calcAge()
     printAge()

main()


# Parameter passing version

def getYear(prompt):
     year = None
     while year is None:
         try:
             year = int(raw_input(prompt))
         except ValueError:
             pass
     return year

def calcAge(start, end):
     return end - start

def printAge(age):
     print "*"*age
     print "You are", age, "years."


def main():
     birth_year = getYear('What year were you born? ')
     current_year = getYear('What year is it now? ')
     age = calcAge(birth_year, current_year)
     printAge(age)

main()

In this case, the fact that getYear() in the global version assigns
to the global "year" when you need to work with two different year
is an inconvenience. If you imagine that you'd do something like
"when was X born, when was Y born, when was Z born, then Y is oldest",
you'll see that it's really stupid to have your functions write to
globals instead of returning values directly to the caller of the
function.



More information about the Python-list mailing list