[Tutor] dict vs several variables?

Steven D'Aprano steve at pearwood.info
Sat Feb 18 04:59:31 CET 2012


Leam Hall wrote:
> I'm building a program that uses one of my own modules for a bunch of 
> formula defs and another module for the tkinter GUI stuff. There are 
> half a dozen input variables and about the same in calculated variables. 
> Is it better/cleaner to just build a global dict and have everything go 
> into it or pass multiple arguments to each function and have it return 
> the calculated value?


A global dict is like the Dark Side of the Force: easier, quicker, simpler, 
but it leads to pain and anguish and great suffering.

I assume you understand why global variables should be avoided as much as 
possible? E.g.

# Bad! Wrong! Do not do this!
x = ''
y = ''
z = ''

def get_user_input():
     global x, y
     x = raw_input("Please enter x: ")
     y = raw_input("Please enter y: ")

def do_calculation():
    global z
    z = "The answer is %s" % (x.upper() + y.lower())

def main()
     get_user_input()
     do_calculation()
     print z


If you're not familiar with the reasons to avoid global variables, you should 
google for "Global variables considered harmful", or start here:

http://c2.com/cgi/wiki?GlobalVariablesAreBad


Well, using a single global dict is *almost* as bad, and for most of the same 
reasons:

# Do not do this either.
values = {'x': '', 'y': '', 'z': ''}

def get_user_input(values):
     values['x'] = raw_input("Please enter x: ")
     values['y'] = raw_input("Please enter y: ")

def do_calculation(values):
    x = values['x']
    y = values['y']
    values['z'] = "The answer is %s" % (x.upper() + y.lower())

def main()
     get_user_input(values)
     do_calculation(values)
     print values['z']


This is a mild improvement, at least you can pass in an alternative dict if 
needed, but it still suffers from failure of encapsulation (all functions that 
have access to the dict have access to all variables, whether they need them 
or not) and other problems.

Just about the only valid use of this pattern I can think of is for global 
settings that apply application-wide. Such settings tend to be write-once, 
which mitigates the disadvantages of global and pseudo-global variables.

By the way, in case it isn't obvious, changing from a dict to a instance with 
named attributes values.x values.y values.z is just a cosmetic change, it 
doesn't change the basic problems.

For a toy problem like the above, it might seem hardly worth the hassle of 
de-globalising the functions, but for real code this really pays off in fewer 
bugs and easier maintenance:


def get_user_input():
     x = raw_input("Please enter x: ")
     y = raw_input("Please enter y: ")
      return (x, y)

def do_calculation(x, y):
    return "The answer is %s" % (x.upper() + y.lower())

def main()
     a, b = get_user_input()
     result = do_calculation(a, b)
     print result


I assume the problem you are solving is more than just a toy. In that case, 
passing individual variables to only the functions that need them is a better 
solution. RELATED variables that MUST stay together can be collected into data 
structures such as tuples, lists, dicts, or custom classes. But don't be 
tempted to dump everything into one giant dict -- that's barely better than 
using globals.



-- 
Steven


More information about the Tutor mailing list