run time code generation in python

Bengt Richter bokr at oz.net
Sun Oct 12 07:41:34 EDT 2003


On Thu, 9 Oct 2003 13:12:10 +0000 (UTC), Duncan Booth <duncan at NOSPAMrcp.co.uk> wrote:

>"Carlo v. Dango" <amigo at fake.not> wrote in
>news:Xns940F929A63B436020206 at 172.16.0.1: 
>
>> 
>> Hello there. I have found a need to runtime generate a method and
>> instert it into an object instance. The code is a simple forwarding
>> mechanism like 
>> 
>> def foo(self, *args, **kwargs):
>>     self.i.foo(*args, **kwargs)
>> 
>> method.. however, it is only at runtime that I know the name "foo" so
>> I cannot gerenate such a method any sooner. 
>
>I don't see why you need to generate any code at runtime.
>This does the same as your code, only now the name of the function to which 
>you are forwarding the call is stored in a variable:
>
>name = 'foo'
>def foo(self, *args, **kwargs):
>    getattr(self.i, name)(*args, **kwargs)
>
>You should be aware that if you store a function in an instance at runtime, 
>the magic binding to 'self' won't happen. You either need to store the 
>function in the class, or leave out the self parameter if you want to 
>insert it into an instance. Something like this may be what you need:
>
I don't quite understand the background motivation, but you can store
bound methods as attributes of arbitrary instances. They can happen to
be bound to the same instance or not (see switcheroos below):
Note that they can shadow methods of the same name, do deleting reveals
the class-defined methods.

 >>> class Foo(object):
 ...     def __init__(self, name): self.name=name
 ...     def foometh(self, other):
 ...         print 'foometh bound to self named %r' %self.name
 ...         print 'name of other instance: %r'% other.name
 ...
 >>> foo = Foo('alice')
 >>> bar = Foo('bob')
 >>> foo.foometh(bar)
 foometh bound to self named 'alice'
 name of other instance: 'bob'
 >>> bar.foometh(foo)
 foometh bound to self named 'bob'
 name of other instance: 'alice'
 >>> foo.bar = bar.foometh
 >>> bar.foo = foo.foometh
 >>> foo.bar(foo)

You can get to the unbound method via the instance's class, and re bind it

 >>> alice.__class__.speak
 <unbound method Who.speak>
 >>> alice.__class__.speak(bob)
 "My name is 'Bob'"
 >>> alice.__class__.speak(alice)
 "My name is 'Alice'"
 >>> bound_bob = alice.__class__.speak.__get__(bob)
 >>> bound_bob()
 "My name is 'Bob'"
 >>> bound_alice = alice.__class__.speak.__get__(alice)
 >>> bound_alice()
 "My name is 'Alice'"
 >>> bob.alice = bound_alice
 >>> bob.alice()
 "My name is 'Alice'"
 >>> bob.bob = bound_bob
 >>> bob.bob()
 "My name is 'Bob'"
 >>> bob.speak()
 "My name is 'Bob'"

(I left the class out of those __get__ calls. Not sure when that will cause a
problem).


>def forwarder(obj, name):
>    def fwd(*args, **kwargs):
>        getattr(obj.i, name)(*args, **kwargs)
>    return fwd
>
>something.foo = forwarder(something, 'foo')
>something.foo(42) # Calls something.i.foo(42)
>
>Alternatively:
>
>def forwarder(obj, name):
>    def fwd(*args, **kwargs):
>        getattr(obj, name)(*args, **kwargs)
>    return fwd
>
>something.foo = forwarder(something.i, 'foo')
>something.foo(42) # Calls something.i.foo(42)
>
>(I'm assuming you want a bit more in the function definition, otherwise of 
>course, 'something.foo=something.i.foo' is an even easier solution).
>
I was wondering about that too. The larger picture is still unclear to me ;-)

Regards,
Bengt Richter




More information about the Python-list mailing list