On 22/08/13 22:36, Matthew Ngaha wrote:
I'm always told to avoid using them. I read discussions on the python
irc channel about them but honestly i feel there are some times where
i can't avoid using them. Like where i want to keep track of a state
variable in many different functions that may or may not alter its
value and also not wanting any of the functions to return it to the
caller.

My question is how many global variables did your last decent sized
program have? Also please share any insight you have about them. I do
try to avoid them, but is this always possible?

Good question! And one that needs a long answer.

Yes, it is possible to avoid global variables. The proof of this, if you need 
any, is programming languages like Haskell which are purely functional 
languages, which means they don't have variables at all! Everything is a fixed 
value, usually created on the fly as needed, and thrown away when no longer 
required, but never modified[1]. Need to change something? You create a new 
value rather than modify an existing one. Haskell programmers are capable of 
writing large programs, and they do it without global variables.

Functional programming is a very different paradigm, and one which takes a 
while to get used to. Haskell, which is pure functional, can be hard to wrap 
your head around, but Python is strongly influenced by Haskell and Lisp and 
could be considered a semi-functional language. If you've ever used list 
comprehensions or generator expressions, you've got a small taste of functional 
programming.

Truth be told, you *could* write a large, non-trivial Python program in 
entirely functional style, but without a clever Lisp or Haskell compiler behind 
it, it would probably be just as slow to run as it would be hard to write. In 
Python, you should consider global variables to be something to be minimized 
rather than entirely avoided.

In my experience, global variables are well-suited to dealing with user 
preferences and command-line options, and otherwise best avoided. But notice 
that user prefs and cmd line options aren't exactly *variables*, since they are 
typically set once, when the program starts up, and then never -- or at least 
hardly ever -- changed. Your functions may read their value, but they will not 
usually change their value.

That brings us to why global variables are unsafe. They're not unsafe because 
they are global. Global constants, or almost-constants, are perfectly fine. 
They're unsafe because they vary unpredictably. They introduce coupling between 
functions which otherwise should be independent.

For example, suppose we have a global variable and three functions, f, g, h, 
all of which read and write to the global under various situations. Now suppose 
you call f() -- the result you get depends on whether or not g() or h() have 
been called first, since they may change the global. And likewise, the result 
g() gives depends on whether or not f() or h() have been called, and similarly 
for h(). So instead of the result of f() depending in a nice clean way only on 
the arguments passed to it, instead it depends in a messy, convoluted, 
confusing way on the history of calls to separate functions that may have 
nothing to do with f(). You now have a tangle of couplings between functions:

f depends on g and h
g depends on f and h
h depends on f and g

Now imagine ten globals and twenty functions.

Globals introduce "action at a distance". A function in one part of your 
program can reach out over a great distance and effect another function's result, just by 
changing a global. That's a bad thing and should be minimized or eliminated.

So the real problem here is *state*. If your functions didn't depend on mutable 
state, but only on arguments passed to them, the problem of action at a 
distance would go away. This is where functional programming comes in: they 
eliminate mutable state altogether. Once a value is created, you can't change 
it, only throw it away and create a new one. In Python we don't necessarily go 
quite to that extreme, but it's still a good ideal to work towards.

One mistake people have is to create a class just to hold global variables, and then 
think that they are virtuous because "it's not a global". So then they end up 
with something like this:

class Everything_I_Need:
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3
        # etc.

everything = Everything_I_Need()


f(everything)
g(everything)
h(everything)


but of course this is just global variables in disguise, and still suffers from 
the same problem with strong coupling and action at a distance.



[1] Never say never. Haskell actually does have a way to create modifiable values, but to 
get an idea of how people consider it, it is often called the "unsafePerformIO 
hack".


--
Steven
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to