Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #21087 > unrolled thread

exec

Started byRolf Wester <rolf.wester@ilt.fraunhofer.de>
First post2012-03-01 14:07 +0100
Last post2012-03-02 08:26 +0100
Articles 9 — 6 participants

Back to article view | Back to comp.lang.python


Contents

  exec Rolf Wester <rolf.wester@ilt.fraunhofer.de> - 2012-03-01 14:07 +0100
    Re: exec Jean-Michel Pichavant <jeanmichel@sequans.com> - 2012-03-01 14:46 +0100
    Re: exec Arnaud Delobelle <arnodel@gmail.com> - 2012-03-01 14:13 +0000
    Re: exec Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-03-01 14:21 +0000
    Re: exec Rolf Wester <rolf.wester@ilt.fraunhofer.de> - 2012-03-01 16:58 +0100
      Re: exec Michael Ströder <michael@stroeder.com> - 2012-03-01 17:26 +0100
      Re: exec Peter Otten <__peter__@web.de> - 2012-03-01 18:14 +0100
        Re: exec Rolf Wester <rolf.wester@ilt.fraunhofer.de> - 2012-03-01 18:23 +0100
      Re: exec Peter Otten <__peter__@web.de> - 2012-03-02 08:26 +0100

#21087 — exec

FromRolf Wester <rolf.wester@ilt.fraunhofer.de>
Date2012-03-01 14:07 +0100
Subjectexec
Message-ID<4f4f7527$1@news.fhg.de>
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)

This works, but I have to call sqr with a.sqr(a, 2), a.sqr(2) does not work
(TypeError: sqr() takes exactly 2 arguments (1 given)).

Is there a possibility to define methods using exec and getting normal behavior?

I would be very appreciative for any help.

With kind regards
Rolf Wester

[toc] | [next] | [standalone]


#21088

FromJean-Michel Pichavant <jeanmichel@sequans.com>
Date2012-03-01 14:46 +0100
Message-ID<mailman.320.1330609611.3037.python-list@python.org>
In reply to#21087
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)
>
> This works, but I have to call sqr with a.sqr(a, 2), a.sqr(2) does not work
> (TypeError: sqr() takes exactly 2 arguments (1 given)).
>
> Is there a possibility to define methods using exec and getting normal behavior?
>
> I would be very appreciative for any help.
>
> With kind regards
> Rolf Wester
>
>
>   
I'll try to ignore you are using the exec statement which is an error :o)

a.sqr(2) would have worked only if sqr was a *bound* method.

print a.sqr
<function sqr at 0x94ecd14>


to oppose to
print a.__init__
<bound method A.__init__ of <__main__.A instance at 0x948734c>>


You cannot dynamically bind a method, however you can do the following.

cmd = "def sqr(x):\n    return x**2\nself.sqr = sqr\n"



http://docs.python.org/reference/datamodel.html : <http://docs.python.org/reference/datamodel.html>
"It is also important to note that user-defined functions which are attributes of a class instance are not converted bound methods; this only happens when the function is an attribute of the class. "

JM

[toc] | [prev] | [next] | [standalone]


#21092

FromArnaud Delobelle <arnodel@gmail.com>
Date2012-03-01 14:13 +0000
Message-ID<mailman.322.1330611223.3037.python-list@python.org>
In reply to#21087
On 1 March 2012 13:07, Rolf Wester <rolf.wester@ilt.fraunhofer.de> 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)
>
> This works, but I have to call sqr with a.sqr(a, 2), a.sqr(2) does not work
> (TypeError: sqr() takes exactly 2 arguments (1 given)).

I'm curious to know your motivation for doing this.

-- 
Arnaud

[toc] | [prev] | [next] | [standalone]


#21093

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-03-01 14:21 +0000
Message-ID<4f4f85eb$0$29989$c3e8da3$5496439d@news.astraweb.com>
In reply to#21087
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

[toc] | [prev] | [next] | [standalone]


#21095

FromRolf Wester <rolf.wester@ilt.fraunhofer.de>
Date2012-03-01 16:58 +0100
Message-ID<4f4f9d55$1@news.fhg.de>
In reply to#21087
Hi,

thanks for your replies so far.

The reason to use exec is just laziness. I have quite a lot of classes
representing material data and every class has a number of parameters.
The parameter are Magnitude objects (they have a value and a unit and overloaded
special functions to correctly handle the units). I want to have getter
functions that either return the Magnitude object or just the value:

iron = Iron()
iron.rho(0) => value
iron.rho() => Magnitude object

def rho(self, uf=1):
    if uf == 1:
        return self._rho
    else:
	return self._rho.val

And because this would mean quite a lot of writing I tried to do it with exec.

With kind regards
Rolf Wester

[toc] | [prev] | [next] | [standalone]


#21097

FromMichael Ströder <michael@stroeder.com>
Date2012-03-01 17:26 +0100
Message-ID<jio7ur$ljn$1@dont-email.me>
In reply to#21095
Rolf Wester wrote:
> The reason to use exec is just laziness.

The worst reason for using it. So I hope you carefully read Steven's comment 
and get rid of exec() for anything serious:

<4f4f85eb$0$29989$c3e8da3$5496439d@news.astraweb.com>

Ciao, Michael.

[toc] | [prev] | [next] | [standalone]


#21098

FromPeter Otten <__peter__@web.de>
Date2012-03-01 18:14 +0100
Message-ID<mailman.328.1330622109.3037.python-list@python.org>
In reply to#21095
Rolf Wester wrote:

> The reason to use exec is just laziness. I have quite a lot of classes
> representing material data and every class has a number of parameters.
> The parameter are Magnitude objects (they have a value and a unit and
> overloaded special functions to correctly handle the units). I want to
> have getter functions that either return the Magnitude object or just the
> value:
> 
> iron = Iron()
> iron.rho(0) => value
> iron.rho() => Magnitude object
> 
> def rho(self, uf=1):
>     if uf == 1:
>         return self._rho
>     else:
> return self._rho.val
> 
> And because this would mean quite a lot of writing I tried to do it with
> exec.

Make the Magnitude class callable then:

>>> class Magnitude(object):
...     def __init__(self, value):
...             self.value = value
...     def __call__(self, uf=1):
...             if uf == 1:
...                     return self
...             return self.value
...
>>> class Iron(object):
...     def __init__(self):
...             self.rho = Magnitude(42)
...
>>> iron = Iron()
>>> iron.rho()
<__main__.Magnitude object at 0x7fb94062be10>
>>> iron.rho(0)
42

[toc] | [prev] | [next] | [standalone]


#21099

FromRolf Wester <rolf.wester@ilt.fraunhofer.de>
Date2012-03-01 18:23 +0100
Message-ID<4f4fb151$1@news.fhg.de>
In reply to#21098
Thank you, that really made things much easier and admittedly much less nasty too.

Regards
Rolf

On 01/03/12 18:14, Peter Otten wrote:
> Rolf Wester wrote:
> 
>> The reason to use exec is just laziness. I have quite a lot of classes
>> representing material data and every class has a number of parameters.
>> The parameter are Magnitude objects (they have a value and a unit and
>> overloaded special functions to correctly handle the units). I want to
>> have getter functions that either return the Magnitude object or just the
>> value:
>>
>> iron = Iron()
>> iron.rho(0) => value
>> iron.rho() => Magnitude object
>>
>> def rho(self, uf=1):
>>     if uf == 1:
>>         return self._rho
>>     else:
>> return self._rho.val
>>
>> And because this would mean quite a lot of writing I tried to do it with
>> exec.
> 
> Make the Magnitude class callable then:
> 
>>>> class Magnitude(object):
> ...     def __init__(self, value):
> ...             self.value = value
> ...     def __call__(self, uf=1):
> ...             if uf == 1:
> ...                     return self
> ...             return self.value
> ...
>>>> class Iron(object):
> ...     def __init__(self):
> ...             self.rho = Magnitude(42)
> ...
>>>> iron = Iron()
>>>> iron.rho()
> <__main__.Magnitude object at 0x7fb94062be10>
>>>> iron.rho(0)
> 42
> 
> 

[toc] | [prev] | [next] | [standalone]


#21128

FromPeter Otten <__peter__@web.de>
Date2012-03-02 08:26 +0100
Message-ID<mailman.343.1330673184.3037.python-list@python.org>
In reply to#21095
Prasad, Ramit wrote:

> Hi Peter,
> 
> >>> class Magnitude(object):
> 
> ...     def __init__(self, value):
> ...             self.value = value
> ...     def __call__(self, uf=1):
> ...             if uf == 1:
> ...                     return self
> ...             return self.value
> ...
> 
> >>> class Iron(object):
> 
> ...     def __init__(self):
> ...             self.rho = Magnitude(42)
> ...
> 
> 
> Why did you make uf=1 instead of None?
> 
> ...     def __call__(self, uf=None):
> ...             if uf is None:

That's a design decision of the OP. I suggested an improvement of the 
implementation and left the interface alone.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web