views:

607

answers:

4

I wrote a class that lets me pass in a list of variable types, variable names, prompts, and default values. The class creates a wxPython panel, which is displayed in a frame that lets the user set the input values before pressing the calculate button and getting the results back as a plot. I add all of the variables to the class using exec statements. This keeps all of the variables together in one class, and I can refer to them by name.

light = Variables( frame , [ ['f','wavelength','Wavelength (nm)',632.8] ,\
                             ['f','n','Index of Refraction',1.0],])

Inside the class I create and set the variables with statments like:

for variable in self.variable_list:
       var_type,var_text_ctrl,var_name = variable
       if var_type == 'f' :  
           exec( 'self.' + var_name + ' = ' + var_text_ctrl.GetValue() )

When I need to use the variables, I can just refer to them by name:

 wl = light.wavelength
 n = light.n

Then I read on SO that there is rarely a need to use exec in Python. Is there a problem with this approach? Is there a better way to create a class that holds variables that should be grouped together, that you want to be able to edit, and also has the code and wxPython calls for displaying, editing, (and also saving all the variables to a file or reading them back again)?

Curt

+17  A: 

You can use the setattr function, which takes three arguments: the object, the name of the attribute, and it's value. For example,

setattr(self, 'wavelength', wavelength_val)

is equivalent to:

self.wavelength = wavelength_val

So you could do something like this:

for variable in self.variable_list:
       var_type,var_text_ctrl,var_name = variable
       if var_type == 'f' :
           setattr(self, var_name, var_text_ctrl.GetValue())
mipadi
+1. setattr was made precisely for setting attributes whose name is known runtime.
RaphaelSP
+1  A: 

I agree with mipadi's answer, but wanted to add one more answer, since the Original Post asked if there's a problem using exec. I'd like to address that.

Think like a criminal.

If your malicious adversary knew you had code that read:

exec( 'self.' + var_name + ' = ' + var_text_ctrl.GetValue() )

then he or she may try to inject values for var_name and var_text_ctrl that hacks your code.

Imagine if a malicious user could get var_name to be this value:

var_name = """
a = 1                 #  some bogus assignment to complete "self." statement
import os             #  malicious code starts here
os.rmdir('/bin')      #  do some evil
                      #  end it with another var_name 
                      #  ("a" alone, on the next line)
a     
"""

All of the sudden, the malicious adversary was able to get YOU to exec[ute] code to delete your /bin directory (or whatever evil they want). Now your exec statement roughly reads the equivalent of:

exec ("self.a=1 \n import os \n os.rmdir('/bin') \n\n "
             "a" + ' = ' + var_text_ctrl.GetValue() ) 

Not good!!!

As you can imagine, it's possible to construct all sorts of malicious code injections when exec is used. This puts the burden onto the developer to think of any way that the code can be hacked - and adds unnecessary risk, when a risk-free alternative is available.

Every time I see Exec, I cry a little. Similarly, I think there's a good reason 'eval' look so similar to 'evil'.
nilamo
I'm not sure if my sensitivity to "exec" and "eval" are because I am paranoid, or because I am a potential criminal... but it definitely causes me to cringe every time.I was led to believe eval was safer. But since you can eval("math.sqrt(4)"), this means you can inject function calls... not good!Avoid eval and exec, especially with user-supplied variables.
There **are** use cases fo eval. Imagine you are doing a spreadsheet. Of course **you have to provide a safe namespace** http://lybniz2.sourceforge.net/safeeval.html
voyager
A: 

For the security conscious, there might be an acceptable alternative. There used to be a module call rexec that allowed "restricted" execution of arbitrary python code. This module was removed from recent python versions. http://pypi.python.org/pypi/RestrictedPython is another implementation by the Zope people that creates a "restricted" environment for arbitrary python code.

kpatvt
A: 

The module was removed because it had security issues. Very difficult to provide an environment where any code can be executed in a restricted environment, with all the introspection that Python has.

A better bet is to avoid eval and exec.

A really off-the-wall idea is to use Google App Engine, and let them worry about malicious code.