Here I am again, same old arguments

Steven D'Aprano steve at REMOVETHIScyber.com.au
Thu Oct 13 08:57:20 EDT 2005


On Thu, 13 Oct 2005 08:05:00 +0000, CJ wrote:

> 1) Why no global variables? I'm taking your word for it that they're bad. Far be it from me to 
> argue with you, but why are they bad ideas to begin with? Most of the languages I've used up to 
> this point have been reliant on globals, so I'm not entirely sure why they shouldn't be used.

Global variables aren't *entirely* bad. I use them myself, sometimes for
constants (well, pseudo-constants -- Python doesn't enforce constants) and
short, quick 'n' dirty throw away code.

But in general, as your code gets bigger and more complicated, using
global variables gets more dangerous, unreliable, harder to debug, and
generally a bad idea. Let me show you some examples.

Suppose you have some some code like this:

# set a global variable
gParrot = 1
# do some work with it
get_shrubbery()
eat_after_dinner_mint()
make_machine_go_ping()
pine_for_the_fjords()
print gParrot

(The names come from Monty Python, as is traditional in Python.)

You have four functions in that piece of code. You expect that after
the four functions run, the code should print 2, but instead it prints
3. Why? Somehow, parrot is getting set to the wrong value. 

Which of those four functions is to blame? Which ones use the global
variable parrot? You can't tell just by looking. Which ones change the
variable? Again, you can't tell. The only way to find out is to read the
code. In a big program, there might be thousands of functions, split over
dozens of modules. Just going backwards and forwards looking up the
functions is hard work.

Now let's re-write that code properly:

# set a variable
parrot = 1
# do some work with it
get_shrubbery(parrot)
parrot = eat_after_dinner_mint()
make_machine_go_ping()
parrot = pine_for_the_fjords()
print parrot

Now it is easier to see what is going on. get_shrubbery uses the value of
parrot, but can't change it. Or rather, if it changes parrot, that change
is local to the function, and doesn't effect anything outside of that
function. So it isn't responsible for the bug.

The machine that goes ping doesn't even use the value of parrot, and it
certainly doesn't change it. So it can't be responsible for the bug.

The value of parrot gets changed in only two places, once by
eat_after_dinner_mint, and the other by pine_for_the_fjords. So you have
halved the amount of places that you need to look for the bug.

What else is wrong with globals?

(1) You can't be sure what a function does without reading and
understanding every bit of code. Suppose you have a function that is
supposed to make the machine go ping, and return True if the machine
pinged and False if it didn't. But you don't know if it changes any global
variables -- that is what we call a "side-effect". Like side-effects in
medicine, it makes it very hard to tell what a function will do.

(2) Global variables allow indiscriminate access. You can't prevent other
functions from messing them up. If you are writing a small program on your
own, maybe you can trust yourself not to accidentally mangle the global
variable. But if you are working on a big project with ten other
programmers, and they all are writing code that reads and writes to your
global variables, can you really trust that none of them will put the
wrong value there?

(3) Globals make it really hard to change your code. You have a global
variable and you want to change what it stands for. But you can't, because
all these dozens of other functions rely on it. So you end up leaving the
old global there, and inventing a new one, and now you have twice as many
places that bugs can be hiding because every function can potentially mess
up two globals instead of one.

(4) It is easy to screening globals accidentally, a source of bugs. You
have a global called "parrot", but somewhere in a function you create a
local variable also called "parrot". Now you have lost access to the
global. This can be a source of many puzzling bugs.

(5) Dependency: global variables mean that different functions and modules
depend on each other in ways that are very hard to control. This means
that any time you modify a function that uses globals, you could
potentially be breaking *any other function*, even if the change you made
to the first function is not a bug.

(6) Error propagation. A bug in one function will propagate to other
functions. This can mean that you detect the bug in a piece of code a
long, long way away from where the bug was introduced. 



> 2) Why no for loop with an index? Again, far be it from me to argue, but it seemed perfect for 
> my program. 

Why do work that you don't have to?

You are writing code like this:

myList = ["spam", "ping", "parrot", "fjords"]
for indx in range(len(myList)):
    print myList[indx],

It prints:
spam ping parrot fjords

But look at how much work you have to do: first you count the length of
the list with len(myList), then you create a list of integers between 0
and that length with range, then for each of those integers, you have to
look up the item in myList. To understand the code, you have to work
through those three things in your head.

Here is a simpler way of doing it:

myList = ["spam", "ping", "parrot", "fjords"]
for item in myList:
    print item,

Translate that into English: For each item in myList, print the item. The
code practically explains itself, you don't have to do all these
intermediate calculations, and there are fewer places for bugs to hide.



> 3) Where do I find a command list, with syntax and all that fun stuff
> for Python? I've explored the python site to no end, but I can't seem to
> find a list.

Have you looked here?

http://docs.python.org/index.html



-- 
Steven.




More information about the Python-list mailing list