A Globals Module pattern

Two comments on my recent posts on a Globals Class pattern for Python and an Arguments Container pattern reminded me that there is one more container for globals that is worth noting: the module.

The idea is a simple one. You can use a module as a container.

Most introductions to Python tell you all about how to get stuff — that is, how to import stuff — *from* imported modules. They talk very little about writing stuff *to* imported modules. But it can be done.

Here is a simple example.

Let’s start with the intended container module, mem.py. I’d show you the contents of mem.py, except for the fact that there aren’t any. mem.py is empty.

Next let’s look at two modules that import and use mem.py.

The caller module is leader.py. Note that it imports mem and also imports the subordinate module, minion.  (Note the use of the print() function; we’re running Python 3 here.)

"leader.py"
import mem
import minion

mem.x = "foo"
print("leader says:",mem.x)
minion.main()
print("leader says:",mem.x)

print()

mem.x = "bar"
print("leader says:",mem.x)
minion.main()
print("leader says:",mem.x)

The subordinate module is minion.py.

"minion.py"
import mem

def main():
	print("minion says:",mem.x)
	mem.x = "value reset by minion from " + mem.x

If you run leader.py it imports minion and mem, and uses mem as a container for variable x.  It assigns a value to x in mem and calls minion, which reads mem.x and resets mem.x’s value, which leader then reads.

When you run leader.py, you see this output:

leader says: foo
minion says: foo
leader says: value reset by minion from foo

leader says: bar
minion says: bar
leader says: value reset by minion from bar

Note that leader.py passes no arguments to minion.main() and minion.main() doesn’t return anything (other than None, of course). Leader and minion communicate solely by means of the variables set in mem. And the communication is clearly two-way. Leader sets values that minion reads, and minion sets values that leader reads.

So what we have here, in mem, is a truly global container. It is not “module global” as in the Globals Class pattern. It is “application global” — it is global across the multiple modules that make up an application.  In order to gain access to this container, modules simply import it.

In keeping with the earlier posts’ grandiosity, I will call this use of an imported module the Globals Module pattern.

Every Python programmer is familiar with one special case of the Globals Module pattern. Just rename mem.py to config.py, stuff it with a bunch of constants or configuration variables, and you have a typical Python file for defining constants or setting configuration values. These values are “application global”, available to all module in an application. All they have to do is to import config.py.

Doing a bit of arm-waving, and christening a Globals Module pattern, does one thing.  It reminds us that modules — used as containers for “application global” values – aren’t limited to supplying constants and pre-set values. Modules can also be written to.  The communication between “normal” modules and Globals Modules is a two-way street.

An Arguments Container pattern

In a comment on my earlier post A Globals Class pattern for Python, Mike Müller wrote
“No need for globals. Just explicitly pass your container. In my opinion this is much easier to understand.”

Mike’s comment led me to some further thoughts on the subject.

Suppose you have a number of things — x, y, and z — that you want to make available to many functions in a module.

There are four strategies that you could use. You could

1. pass x, y, and z as individual arguments
2. make x, y, and z globals

or you could create a container C of some sort and

3. pass container C as an argument
4. make container C a global

So you have two basic questions to answer. When you make the things — x, y, and z — available:

A. Do you make them available in global variables, or in arguments that you pass around?

B. Do you make them available individually, or do you put them in some kind of container and make the container available?

My original post assumed that in at least some situations you might answer question A with “use global variables” and then went on to propose that in those situations the best answer to B is “put them in a container”.

Since the point of that post was to point out the usefulness of a class as a container, I called the proposed pattern the Globals Class pattern. But in most cases some other kind of container would do as well as a class. I could almost as easily have called the pattern the Globals Container pattern.

So if you look at these two questions — A and B — I think it is interesting where Mike and I differ, and where we agree.

Question A: args or globals

Where we differ, if you could call it that, is in the answer to A.

Mike wrote “No need for globals. Just explicitly pass your container. In my opinion this is much easier to understand.”

In my post I wrote “Sometimes globals are the best practical solution to a particular programming problem.” But that wasn’t really what the post was about. It was about the answer to question B.

So I can’t really say that Mike and I disagree very much. He says “I like apples”. I say “Sometimes I like an orange.”  No big deal.

Question B — multiple things or a single container

What is much more interesting is that we both agree on the answer to question B: use a container object.

But since I was talking about globals, I was talking about a container for globals.  Since Mike was talking about arguments, he was talking about a container for arguments.

Which means that we have two different patterns. My earlier post was about strategy 4 – a Globals Container pattern. Mike is talking about strategy 3 — what we might call an Arguments Container pattern.

As it happens, I had stumbled onto the Arguments Container pattern myself, not in Python but in Java. The circumstances were very similar to the circumstances that led to the Python Globals Class pattern. I had a lot of variables that I needed to pass around. As the code evolved,the argument lists got longer and harder to manage. Finally I just bundled all of the variables into a single container object and passed the container around. As I needed to add new arguments, I was able to add them to just one place — the container.

At the time, I felt sort of stupid doing this. I hadn’t ever heard of this as a programming technique.  It smacked of sneaking global variables in through the back door, and of course everybody knows that globals are always bad. But it worked, and it made my life a lot easier.

So now Mike comes along and proposes doing exactly the same thing. I feel relieved. I’m not the only one doing this. It may even be a Good Thing.

So I’m happy to announce — not the discovery, certainly — the christening of the Arguments Container pattern, which says, basically:

Sometimes when you have a lot of individual variables that you need to pass around to a lot of different functions or methods, the best solution is to put them into a container object and just pass the container object around.

This is not a specifically Python pattern. And in a way it is No Big Deal. But I’m doing a bit of shouting and arm-waving here because I think that somewhere there is probably at least one person for whom this post might be useful.

A Globals Class pattern for Python

I’ve gradually been evolving a technique of coding in which I put module globals in a class. Recently I stumbled across Norman Matloff’s Python tutorial in which he recommends doing exactly the same thing, and it dawned on me that this technique constitutes a truly idiomatic Python design pattern.

A pattern needs a short, catchy name. I don’t think anyone has yet given this pattern a name, so I will propose the name Globals Class pattern.

I’m sure that many experienced Python programmers are already quietly using the Globals Class pattern. They may not see much point in making a big deal about it, or in giving it a name and decking it out with the fancy title of “design pattern”. But I think a little bit of hoopla is in order. This is a useful technique, and one worth pointing out for the benefit of those who have not yet discovered it.  A bit of cheering and arm-waving is in order, simply to catch some attention.

The technique is extremely simple.

  • You define a class at the beginning of your module.  This makes the class global.
  • Then, all of the names that you would otherwise declare global, you specify as attributes of the class.

Really, there is virtually nothing class-like about this class; for instance, you probably will never instantiate it. Instead of functioning like a true class, it functions as a simple container object.

I like to use the name “mem” (in my mind, short for “GlobalMemory”) for this class, but of course you can use any name you prefer.

All you really need is a single line of code.

        class mem: pass

That is enough to create your mem container. Then you can use it wherever you like.

        def doSomething():
            mem.counter = 0
            ...
        def doMore():
            mem.counter += 1
            ...
        def doSomethingElse():
            if mem.counter > 0:
                ...

If you wish, you can initialize the global variables when you create the class. In our example, we could move the initialization of mem.counter out of the doSomething() function and put it in the definition of the mem class.

        class mem:
            counter = 0

In a more elaborate version of this technique, you can define a Mem class, complete with methods, and make mem an instance of the class. Sometimes this can be handy.

        class Mem:
            def __init__(self):
                self.stupidErrorsCount = 0
                self.sillyErrorsCount  = 0

            def getTotalErrorsCount(self):
                return self.stupidErrorsCount + self.sillyErrorsCount

        # instantiate the Mem class to create a global mem object
        mem = Mem()

What’s the point?

So, what does the Globals Class pattern buy you?

1. First of all, you don’t have to go putting “global” statements all over your code.   The beauty of using a globals class is that you don’t need to have any “global” statements in you code.

There was a time — in the past, when I still used “global” — when I might find myself in a situation where my code was evolving and I needed to create more and more global variables. In a really bad case I might have a dozen functions, each of which declared a dozen global variables. The code was as ugly as sin and a maintenance nightmare.  But the nightmare stopped when I started putting all of my formerly global variables into a global class like mem.  I simply stopped using “global” and got rid of all those “global” statements that were cluttering up my code. 

So the moral of my story is this.  Kids, don’t be like me.  I started out using “global” and had to change.  I’m a recovering “global” user. 

Don’t you even start.  Skip the section on the “global” keyword in your copy of Beginners Guide to Learning Python for Dummies.  Don’t use “global” at all.  Just use a globals class.

2. I like the fact that you can easily tell when a variable is global simply by noticing the mem. modifier.

3. The globals statement is redundant.  The Globals Class pattern relieves us of of the burden of having to worry about it.

Python has the quirk that if X is a global, and a function only reads X, then within the function, X is global. But if the function assigns a value to X, X is treated as local.

So suppose that — as your code evolves — you add an assignment statement deep in the bowels of the function. The statement assigns a value to X. Then you have — as a side-effect of the addition of that statement — converted X (within the scope of the function) from a global to a local.

You might or might not want to have done that.  You might not even realize what you’ve done.   If you do realize what you’ve done, you probably need to add another statement to the function, specifying that X is global.  That is sort of a language wart. If you use the Globals Class pattern, you avoid that wart.

4. I think the use of the Globals Class pattern makes the work of static code analyzers (e.g. PyFlakes) easier.

5. The Globals Class pattern makes it possible to create multiple, distinct groups of globals.

This can be useful sometimes. I have had modules that processed nested kinds of things: A, B, and C. It was helpful to have different groups of globals for the different kinds of things.

        class memA: pass
        class memB: pass
        class memC: pass

6. Finally, the Globals Class pattern makes it possible to pass your globals as arguments.

I have had the situation where a module grew to the point where it needed to be split into two modules. But the modules still needed to share a common global memory. With the Globals Class pattern, a module’s globals are actually attributes of an object, a globals class.  In Python, classes are first-class objects.  That means that a globals class can be passed — as a parameter — from a function in one module to a function in another module.

Is this really A Good Thing?

At this point I can hear a few stomachs churning. Mine is one of them. Because, as we all know, Global Variables are Always a Bad Thing.

But that proposition is debatable.  In any event, it is an issue that I’m not going to explore here.  For now, I prefer to take a practical, pragmatic position:

  • Sometimes globals are the best practical solution to a particular programming problem.
  • For the occasions when Globals are A Good Thing, it is handy to have a way to Do Globals in A Good Way.

So the bottom line for me is that there are occasions when some kind of globals-like technique is the best tool for the job.  And on those occasions the Globals Class pattern is a better tool for the job than globals themselves.