Reputation: 1789
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?
Upvotes: 10
Views: 6524
Reputation: 122870
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
Upvotes: 17
Reputation: 18389
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 Foo
s 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.
Upvotes: 3