exec

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Mar 1 09:21:31 EST 2012


On Thu, 01 Mar 2012 14:07:15 +0100, Rolf Wester wrote:

> Hi,
> 
> I would like to define methods using exec like this:
> 
> class A:
>     def __init__(self):
>         cmd = "def sqr(self, x):\n    return x**2\nself.sqr = sqr\n"
>         exec cmd
> a = A()
> print a.sqr(a, 2)


That's... nasty, nasty code. I would hate to have to maintain that. I 
hope you have a VERY good reason for doing it instead of the more obvious:

class B:
    def __init__(self):
        def sqr(self, x):
            return x**2
        self.sqr = sqr


or the even more obvious:

class C:
    def sqr(self, x):
        return x**2


And I *really* hope that you aren't getting the string to be exec'ed from 
untrusted users. The world has enough code injection vulnerabilities.

If you don't understand what a code injection vulnerability is, or why 
using exec on untrusted strings is dangerous, stop what you are doing and 
don't write another line of code until you have read up it. You can start 
here:

http://en.wikipedia.org/wiki/Code_injection
https://www.owasp.org/index.php/Injection_Flaws

and remember, code injection attacks are now the most frequent attack 
vector of viruses, worms and malware, ahead of buffer overflow attacks.


Class C is, of course, the only one where a.sqr is an actual method, that 
is, a.sqr(5) works instead of a.sqr(a, 5). You can fix this by doing one 
of the following:

(1) Your function sqr() doesn't actually use self, so why require it? Get 
rid of it!

class A:
    def __init__(self):
        # still nasty...
        cmd = "def sqr(x):\n    return x**2"
        exec cmd 
        self.sqr = sqr  # or put this in the cmd string (yuck)


class B:
    def __init__(self):
        # better, but still weird
        def sqr(x):
            return x**2
        self.sqr = sqr



(2) Perhaps you actually do need access to self. So turn the function 
into a proper method.


from types import MethodType

class A:
    def __init__(self):
        # still nasty...
        cmd = "def sqr(self, x):\n    return x**2\n"
        exec cmd 
        self.sqr = MethodType(sqr, self)

class B:
    def __init__(self):
        def sqr(self, x):
            return x**2
        self.sqr = MethodType(sqr, self)


(3) My guess is that there is probably some sort of closure-based 
solution that will work, or delegation, or composition. But given the toy 
example you have shown, I don't know what that might be. If you explain 
what you are actually doing, perhaps someone can suggest a better 
solution.



-- 
Steven



More information about the Python-list mailing list