[Tutor] I Give Up. - Follow up post

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Tue Jul 4 20:41:32 CEST 2006


> I tried it by opening a file , but could find no way to do variable 
> variables


Hi Brian,

Look for the concept of dictionaries in Python.  "Variable variables" in 
languages like PHP and Perl are doable in Python, but a dictionary usually 
handles such situations in a safer way.


> and then read it in as a file , which builds an array (AKA dictionary)
> and then just assign thus:
>
> foreach ($filearray as $key => $value)
> {
> 	$$key = $value
> }

This is not safe in Python, because the $key given could easily be the 
name of something that shouldn't be treated as configuration, such as the 
built-in functions.  It also makes debugging a bit harder if we have 
variables in a program that aren't explicitely named.

The safe way to do this is to sandbox these variables in a dictionary. 
Conceptually, the pseudocode looks like:

################################
config_options = {}
for (name, value) in the file:
     config_options[name] = value
################################

and the real code to do this doesn't look too much different.



Let's look at some of the config-reading code:

>     if cfg.has_section("Parameters"):
>         myparams = cfg.items("Parameters")
>         for item in myparams:
>             parameter[item[0]] = item[1]
>     else:
>         log_error("Parameters","not found")
>     if cfg.has_section("Ports"):
>         ports = cfg.items("Ports")
>         for port in ports:
>             watch_port[port[0]] = port[1]
>     else:
>         log_error("Ports","Not Found")
>     if cfg.has_section("Hosts"):
>         hostnames = cfg.items("Hosts")
>         for hostname in hostnames:
>             watch_hosts[hostname[0]] = hostname[1]
>     else:
>         log_error("Hosts","Not Found")
>     if cfg.has_section("IP Addresses"):
>         ips = cfg.items("IP Addresses")
>         for ip in ips:
>             watch_ips[ip[0]] = ip[1]
>     else:
>         log_error("IP Addresses","Not Found")
>     if cfg.has_section("Alerts"):
>         alerts_to = cfg.items("Alerts")
>     else:
>         log_error("Hosts","Not Found")


There's a lot of repetition here.  When we have the temptation to copy and 
paste, try to see if a helper function can do some lifting.

In fact, there's a bug there because of the copy-and-paste.  If there are 
no Alerts, the system will spuriously blame Hosts.  I resent being blamed 
for things I don't do, and I'm sure my programs feel the same.  *grin*

Here's a possible refactoring:

#########################################################
def read_config_section(section_name, output_dictionary):
     if cfg.has_section(section_name)
         section = cfg.items(section_name)
     else:
         log_error(section_name, "Not Found")
     for key_value in section:
         output_dictionary[key_value[0]] = key_value[1]
#########################################################

Once we have this, we can then do:

     read_config_section("Parameters", parameter)
     read_config_section("Ports", watch_port)
     ...

and eliminate a lot of that repetitive code.


Does this make sense?  Feel free to ask more questions.


More information about the Tutor mailing list