When to use globals

I am dogmatic about never using global variables. But when people way smarter than me use them, like Brian Kernighan does when he builds a command-line interpreter in that chapter of The Unix Programming Environment, I wonder if maybe I’m being too reluctant.

I was looking at a python module vaguely like this:

def foo():
do_foo_stuff()

def bar():
do_bar_stuff()

def baz():
do_baz_stuff()

def quux():
do_quux_stuff()

I had a bunch of independent functions. I wanted to add logging. I saw two easy ways to do it:

def foo():
logger = get_logging_singleton()
logger.log_stuff()
do_foo_stuff()

def bar():
logger = get_logging_singleton()
logger.log_stuff()
do_bar_stuff()

def baz():
logger = get_logging_singleton()
logger.log_stuff()
do_baz_stuff()

def quux():
logger = get_logging_singleton()
logger.log_stuff()
do_quux_stuff()

In the above code, I would get a reference to my logger object in each function call. No globals. Maybe I am violating some tenet of dependency injection, but I’ll talk about that later. Anyhow, the point I want to make is that the above approach is the way I would do it in the past.

Here’s how I decided to write it this time:

logger = get_logging_singleton()

def foo():
logger.log_stuff()
do_foo_stuff()

def bar():
logger.log_stuff()
do_bar_stuff()

def baz():
logger.log_stuff()
do_baz_stuff()

def quux():
logger.log_stuff()
do_quux_stuff()

All the functions access the logger created in the main namespace of the module. It feels a tiny bit wrong, but I think it is the right thing to do. The other way violates DRY in a big fat way.

So, a third option would be to require the caller to pass in the logging object in every function call, like this:

def quux(logger):
logger.log_stuff()
do_quux_stuff()

This seems like the best possible outcome — it satisfies my hangup about avoiding global variables and the caller can make decisions about log levels by passing any particular logger it wants to.

There’s two reasons why I didn’t take this approach:

  1. I was working on existing code, and I didn’t have the option of cramming in extra parameters in the calling library. So, I could do something like def quux(logger=globally_defined_logger) but I’m trying to make this prettier, not uglier. The whole reason that I wanted to add logging was that I wanted some visibility into what what the heck was going wrong in my app. I didn’t have time to monkey with overhauling the whole system.
  2. I plan to control my logger behavior from an external configuration system. I don’t want to change code inside the caller every time I want to bump the log level up or down. It is the conventional wisdom in my work environment that I face less risk just tweaking a configuration file setting and restarting my app rather than editing my code*.

[*]I suspect that in the final analysis, this belief will be exposed as garbage. But for right now, it seems pretty true that bugs occur more frequently after editing code than after editing config files.

UPDATE: Apparently, I’m not just talking to myself here! Gary Bernhardt linked to this post and added some really interesting points. Also, his link to the post on the origin of the phrase now you have two problems was something I hadn’t heard of before.

Published by

matt

My name is Matt Wilson and I live in Cleveland Heights, Ohio. I love random emails from strangers, so get in touch! matt@tplus1.com.

  • Or there’s always:


    class Frotz(object):

    def __init__(self, logger=None):
    self.logger = logger or logging.getLogger()

    def foo(self, ...):
    self.logger.log(...)
    ...

    def bar(self, ...):
    self.logger.log(...)
    ...

    Which would seem to be a little happier on the DI front and the cleanliness front. And then your module doesn’t get all fussy about importing if for some reason it can’t get its logger going.

    Though in reality I don’t think you should be swearing off globals entirely; I think perhaps the message has gotten distorted over time. If you have a really good reason, and you know what you’re doing, then it’s probably OK to have the occasional global. I suspect that we mostly shout about the badness of globals so that the first-year comp sci kids get the message that they should pay attention and not start using globals all willy-nilly.

  • Awesome, your blog ate my nice PRE tags, so no properly indented Python code for you (boo hoo). 😛

  • Thanks for the comment. I think I’m one of those people that got yelled at for using globals and now I have a hangup about them.

    Anyhow, you can use the code tag and it will respect whitespace.

  • Thanks for a great post, was an insight into the global variable utility, I am new to programming and have been learning everyday.
    Nice i discovered your post…

  • Nice post, very educating it was.. somehow I have always been avoiding Global variable my friends say they cannot do without Globals.. It was nice to read your post I might want to strat using Globals now..

  • Thanks for an informative post, I am sure will be useful for beginners..

  • Thanks for your post it was nice to know about Globals..

  • I really dont think any programmer can do without globals, thanks for your post, you have some valid points to make.

  • Yes the optimal usage of variables is key to programming..

  • very useful post thanks for putting it up..

  • Yes, thats right.

  • sooo much on Globals at a single post.. great

  • Ben Finney

    The entrenched aversion to globals is usually specifically about *program*-level globals; i.e. identifiers that cross module boundaries and are almost impossible to track down reliably.

    There's nothing wrong with *module*-level globals, which is the largest scope in Python.

  • Somehow I have always been avoiding Global variable my friends say they cannot do without Globals.. It was nice to read your post I might want to strat using Globals now..

    John

  • I echo your sentiment, well for me *module*-level globals had been very beneficial

  • coldblood

    That was really informative.. I really liked the way you explained it.. Appreciate the effort.Thanks.

  • coldblood

    That was really informative..I really had lots of doubts when I was using the global variable but after reading this article half my doubts have been cleared.

  • max191

    Your blog is very interesting. I would like to tell that I have been looking for such information and finally got it. Thanks a lot.
    regards
    charcoal grill

  • This is so interested! Where can I find more like this?

  • I loved the way you exlained things. Much better many here

    respect
    David kalin
    ______________________________________________

  • Than You for code, it will help me a lot

  • thank you for your post,nice,i am appriciate what you said!