Dynamically altering __init__

Kääriäinen Anssi anssi.kaariainen at thl.fi
Thu Oct 13 07:25:52 EDT 2011


Hello all,

I am trying to alter the init method of a class by source to AST -> alter AST
-> AST back to code -> f = types.FunctionType(code, {}, '__init__') ->
mt = types.MethodType(f, None, Foo) -> Foo.__init__ = mt

I have two problems, first I haven't yet figured out how to make the AST back
to code, so that it will be accepted by types.FunctionType. Also, I can't make
the Foo.__init__ be callable with arguments. Here is an example without
using AST:

class Foo(object):
    def __init__(self):
         pass

src = """
def my_init_func(self, *args):
    print "here"
"""

class Foo(object):
    pass

import parser
import types
st = parser.suite(src)
dyn_func = parser.compilest(st)
f = types.FunctionType(dyn_func, {}, '__init__')
im = types.MethodType(f, None, Foo)
Foo()
Foo.__init__ = im
Foo(1, 2, 3)

The result is: TypeError: <module>() takes no arguments (4 given). I have
figured out that when I call f(), I am actually executing the src as is, not
the defined function in the src. But I can't figure out how to get a 
reference to my_init_func.

You might be wondering why I am doing this. I am trying to rewrite this:

class Foo(object):
    attrs = ['spam', 'eggs']
    def __init__(self, *args):
        for attname, val in izip(Foo.attrs, args):
            setattr(self, attname, val)

into this:
...
    def __init__(self, *args):
         self.spam, self.eggs = args

This is done for performance reasons. There is about 2x difference when
creating 10000 objects. While it is a nice improvement, this is still mostly
just for learning purposes.

If you can help me it would be great. I am probably doing a lot of things
wrong, but there isn't too much information available about these shorts
of things. Link to example code would be perfect.

 - Anssi Kääriäinen


More information about the Python-list mailing list