Exec inside a class method to call other class methods?

Carl Banks pavlovevidence at gmail.com
Thu Dec 25 17:53:51 EST 2008


On Dec 25, 12:22 pm, Matthew Dubins <matt.dub... at sympatico.ca> wrote:
> Hello all,
>
> I have made a python script to upload contact information from an excel
> worksheet to an online database.  One part of the program that really
> tripped me up was when I wanted to call specific class methods that I
> had made to deal with specific types of contact information (Parent's
> name, Child's name, Phone #, etc).  My first thought was to make it easy
> using the exec statement.

Bad idea.

You should not use exec and eval unless it's your intention to allow
the user to run arbitrary Python code.

Any other time you think you need to use exec (such as when
constructing an attribute name), you should find out whether there's
another way to do it, and there usually is.  Such is the case here;
there is a function, getattr, that does what you want.  See below.


> The code (a method within a class) looked like this:
> ----------
> def parse(self, data, data_type)
>     exec "self.__parse_%s(data)" % data_type
> ----------

I presume you're aware that the double underscore is a sort of private
variable.  It causes the Python compiler to mangle the name when used
inside a class definition (it converts __parse_email to
_Parser__parse_email under the covers, assuming Parser is the class
name).

Well, it turns out that the Python compiler doesn't know that the
string in the exec statement is part of the class, so it doesn't
mangle the name for you.  If you want to get the method name from
within the exec statement, you have to mangle it by hand, like so:

def parse(self,data,data_ype):
    exec "self._Parser__parse_%s(data)" % data_type


However, you shouldn't do that.  Instead, use getattr, which is a
function that was designed exactly for that purpose, and is much less
of a security risk.

def parse(self,data,data_ype):
    method = getattr(self,"_Parser__parse_%s" % data_type)
    method(data)

Note that you still have to use the mangled version of the name with
getattr (getattr doesn't know it's inside the class, either).  And,
although this is much safer than exec, you should still be wary of
passing user input into it.


Here is why you shouldn't use exec for this.  You say this program
reads data from a spreadsheet.  What would happen if, in the data type
field, a malicious user were to enter the following string (without
surrounding quotes):

"email(); import os; os.system('format c:');"

Your exec statement would blindly execute this, oops, it happened to
format your hard disk.  exec and eval are prone to security holes like
this, and they usually entail a performance penalty (since the
compiler has to be invoked for every call), so please use them only
what they were intended for.


Carl Banks



More information about the Python-list mailing list