[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