Globals or objects?

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Fri Feb 22 15:01:47 CET 2008


On Fri, 22 Feb 2008 03:16:12 -0800, MartinRinehart wrote:

> D'Aprano's discussion is persuasive but only in the case where you do
> not want multiple actors updating a single value. In my case multiple
> actors have legitimate interest in updating the value. (Actors within a
> single thread, fortunately.)

You missed the point. It's not whether you only have *one* actor has to 
update the value, or more than one. It's about having loose coupling 
between the actors and the value.

Consider a thought experiment. Suppose somebody wrote a math library that 
worked something like this:

# contents of maths.py
x = 0.0  # default value for global x

def sin():
    taylor = x + x**2/2 + x**3/6
    # Taylor's expansion of sine. (I think.)
    return taylor


and so forth. To use this library, you would have to do this:

savex = maths.x
maths.x = 0.1
y = maths.sin()  # multiple actors with a legitimate need
z = maths.cos()  # to access a single global value
maths.x = savex


The functions are tightly coupled to x, and can't operate on anything 
else other than x, so your program ends up being filled with wasteful 
code storing the value of x, setting it to a value, then restoring it.

I think we will all agree that the above is a ridiculous way to write 
code. But what you're doing differs from it only in degree, not kind: all 
you're doing is replacing x with counter.

In your example, you say you have "multiple actors [with a] legitimate 
interest in updating the [global] value." That's fine. But that *group* 
of actors still behaves as a single entity. What happens when you have 
two *groups*?

savecounter = counter
foo(actor1)  # All these actors are in the same group:
foo(actor3)  # "Odd" actors.
foo(actor5)
print counter
counter = savecounter
# But these are in a different group:
foo(actor2)  # "Even" actors.
foo(actor4)

As soon as you have multiple groups, globals become a millstone around 
your neck because of that tight coupling: your function foo() can't 
operate on any value except counter. That makes testing very hard, 
because your test functions can't provide their own counters.

Now, there are times where using globals is acceptable *in spite of* this 
problem. For example, I will often use globals to write a piece of quick-
and-dirty through-away code. Or as a first draft: write a bit of code 
using a global, get the basic algorithm working, then modify it to work 
with a parameter instead. Or perhaps you've decided that you really 
*want* that tight coupling. And you can't avoid globals altogether, 
because there's always going to be a global scope.


-- 
Steven



More information about the Python-list mailing list