First - please accept my apologies if this is a duplicate - I have the feeling that I have seen some sort of similar discussion before, but I really cannot find it.
My question regards object composition in Python that should look like inheritance from within each minor of the composite classes. The use case is that multiple object instances share a common core of attributes and their values (and not only a common structure, which would be a classic inheritance case instead).
I could do this with a simple attribute, i.e. by simply having each Class having one attribute called "shared_attributes", which is in itself a class storing all the values:
class CoreClass(object):
def __init__(self):
self.attr = 'asdf'
class CompClass1(object):
def __init__(self, core):
self.core_attr = core
class CompClass2(object):
def __init__(self, core):
self.core_attr = core
But this requires me to access each shared attribute through the class.core_attr
attribute, which I do not want (for several reasons, one of which is that this would require an extensive rewrite of large sections of code).
So, instead I would like to use a composite pattern relying on Python's built-in __getattr__
object method, as such:
class TestClass1(object):
def __init__(self):
self.attr1 = 1
def func_a(self):
return 'a'
class CompClassBase(object):
def __init__(self, test_class):
self.comp_obj = test_class
def __getattr__(self, item):
return getattr(self.comp_obj, item)
class CompClass1(CompClassBase):
def __init__(self, test_class):
CompClassBase.__init__(self, test_class)
self.attr2 = 13
def func_b(self):
return '1b'
class CompClass2(CompClassBase):
def __init__(self, test_class):
CompClassBase.__init__(self, test_class)
self.attr2 = 23
def func_b(self):
return '2b'
if __name__ == '__main__':
tc = TestClass1()
cc1 = CompClass1(test_class=tc)
cc2 = CompClass2(test_class=tc)
print cc1.attr1
print cc1.attr2
print cc1.func_a()
print cc1.func_b()
print cc2.attr1
print cc2.attr2
print cc2.func_a()
print cc2.func_b()
Which prints, as it should, the following:
1
13
a
1b
1
23
a
2b
This pattern fits my needs perfectly, but there is something about it that wants to make me be certain about it ...
EDIT: (to respond to some comments) It is essential that this pattern will share all attributes in the shared class (given the previous objects):
cc1.attr1 = 'this is a test'
cc2.attr1 # must now be 'this is a test' as well!
2nd EDIT: I have used this pattern now for several weeks, and it works beautifully. However, I'm still hoping for some discussion, since I want to include this pattern in my standard toolkit from now on :-)
So now my question to you is simple: Is this a good practice? Does this particular Python pattern have any disadvantages? Should I be aware of some dangers here?