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.

  • http://www.pirnat.com/ Mike Pirnat

    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.

  • http://www.pirnat.com/ Mike Pirnat

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

  • http://tplus1.com matt

    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.

  • http://www.spadepot.com/ Spa Depot

    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…

  • http://www.amoils.com/warts.html Warts Treatment

    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..

  • http://www.animaroo.com/puppies-for-sale/german-shepherd.html German Shepherd Puppies

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

  • http://www.firesprinklersystemsinfo.com/ Sprinklers

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

  • http://www.selectfoam.com/ Mattresses

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

  • http://www.mexicoadventure.com/ Mexico

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

  • http://www.hemroidshelp.com/ hemorrhoid treatment

    very useful post thanks for putting it up..

  • http://www.odlotowewakacje.com/ Last Minute

    Yes, thats right.

  • http://www.pokerhowto.net/ How to play Poker

    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.

  • http://www.club-penguin.org/club-penguin-news/club-penguin-ninja-cardjitsu-upgrades.html club penguin ninja cards

    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

  • http://www.tbcco.com/wheelie-bin-cleaning-equipment.htm bin cleaning equipment

    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

  • http://www.foamrubbermattresses.net/ foam_rubber_mattresses

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

  • http://www.jencoconcrete.com Long Island Concrete

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

    respect
    David kalin
    ______________________________________________

  • http://gpalabs.com/ Essay

    Than You for code, it will help me a lot

  • http://caoch.net/ coach outlet

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