views:

448

answers:

2

How do I add an instance method to a class using a metaclass (yes I do need to use a metaclass)? The following kind of works, but the func_name will still be "foo":

def bar(self):
    print "bar"

class MetaFoo(type):
    __new__(cls, name, bases, dict):
        dict["foobar"] = bar
        return type(name, bases, dict)

class Foo(object):
    __metaclass__ = MetaFoo

>>> f = Foo()
>>> f.foobar()
bar
>>> f.foobar.func_name
'bar'

My problem is that some library code actually uses the func_name and later fails to find the 'bar' method of the Foo instance. I could do:

dict["foobar"] = types.FunctionType(bar.func_code, {}, "foobar")

There is also types.MethodType, but I need an instance that does'nt exist yet to use that. Am I missing someting here?

+2  A: 

I think what you want to do is this:

>>> class Foo():
...   def __init__(self, x):
...     self.x = x
... 
>>> def bar(self):
...   print 'bar:', self.x
... 
>>> bar.func_name = 'foobar'
>>> Foo.foobar = bar
>>> f = Foo(12)
>>> f.foobar()
bar: 12
>>> f.foobar.func_name
'foobar'

Now you are free to pass Foos to a library that expects Foo instances to have a method named foobar.

Unfortunately, (1) I don't know how to use metaclasses and (2) I'm not sure I read your question correctly, but I hope this helps.

Note that func_name is only assignable in Python 2.4 and higher.

Nathan Sanders
+7  A: 

Try dynamically extending the bases that way you can take advantage of the mro and the methods are actual methods:

class Parent(object):
    def bar(self):
        print "bar"

class MetaFoo(type):
    def __new__(cls, name, bases, dict):
     return type(name, (Parent,) + bases, dict)

class Foo(object):
    __metaclass__ = MetaFoo

if __name__ == "__main__":
    f = Foo()
    f.bar()
    print f.bar.func_name
Aaron Maenpaa
What if I want to create several methods that reference the 'bar' implementation?
Knut Eldhuset