This question was denied on StackExchange, and I haven't found an answer yet on StackOverflow.
Note: the code does work, and I'm asking about ideas, better options and opinions (performance, reliability) to extend class instances at runtime.
For example, let's say my original class is Foo and I want to "extend it" with Bar.
The specific constraints I have now is:
I wonder if there is something to do with new, metaclass, or mix-ins. But I did not achieve anything with those yet.
Using as a base:
class Foo:
def foo(self): return 'foo'
class Bar:
def bar(self): return self.foo() + 'bar'
foo = Foo()
It works, but it creates a new object and I wanted to do without doing so (and I think that the test is a useless overhead):
class Bar(Foo, object):
def __init__(self, foo):
self.__foo = foo
def __getattr__(self, name):
try:
return getattr(self.__foo, name)
except:
raise AttributeError
def bar(self):
return self.foo() + 'bar'
bar.foo() # OK
bar.bar() # OK
isinstance(bar, Foo) # OK
isinstance(bar, Bar) # OK
Almost worked, but Bar does not appear in inheritance:
foo.__class__.__dict__.update(Bar.__dict__)
foo.bar() # does work
isinstance(foo, Foo) # True
isinstance(foo, Bar) # False :(
Almost, but Bar does not appear in inheritance and I have to test if the attribute I'm patching is a callable or not:
for k, v in Bar.__dict__.iteritems():
if callable(v):
setattr(foo, k, types.MethodType(v, foo))
foo.foo() # OK
foo.bar() # OK
isinstance(foo, Foo) # OK
isinstance(foo, Bar) # False
Please enlighten me.
CAVEAT: This is not clean programming! But you knew that :-)
The easiest thing to do is to make Bar be a subclass of Foo, and then dynamically change the type of your instance:
class Foo:
def foo(self): return 'foo'
class Bar(Foo):
def bar(self): return self.foo() + 'bar'
foo = Foo()
foo.__class__ = Bar
print foo.bar()
In response to a question in a comment:
>>> class Foo:
... def foo(self): return 'foo'
...
>>> class Bar(Foo):
... def bar(self): return self.foo() + 'bar'
...
>>> foo = Foo()
>>>
>>> foo.__class__ = Bar
>>>
>>> print foo.bar()
foobar
>>> isinstance(foo, Bar)
True
>>> isinstance(foo, Foo)
True
In response to another comment: yes, it really is that easy :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With