11

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):
    def __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
  • Why are you trying to change the name of the method? doesn't dict[bar.func_name] = bar accomplish what you want? Commented Sep 15, 2008 at 19:03
  • Good question... I was originally creating method names based on attributes defined in the dict, but I realize this is pointless if the implementations of the methods are identical. Commented Sep 15, 2008 at 19:30

2 Answers 2

17

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

python 3:

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(metaclass=MetaFoo): 
    ...

f = Foo()
f.bar()

print(f.bar.__qualname__)

python 2:

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
Sign up to request clarification or add additional context in comments.

2 Comments

What if I want to create several methods that reference the 'bar' implementation?
Hi Aaron, it works fine but if you try to create a new class NewFoo that inherits from Foo you get an inheritance error due to MRO issues. I tried to solve this problem with a similar approach: github.com/tierratelematics/pypom_form/blob/refactor/pypom_form/… but I don't know if it is the best approach or if there is a more pythonic way to do so. It should work fine on Python 3 too
3

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.