When you want a class instance to act as if it was an instance of another class (at least from some aspect), but for some reason you can't use multiple inheritance, You have to deal with some kind of "delegation": You embed an object of the other instance as an attribute of your main instance, and then create as much attributes as you can that "point to" corresponding attribute of the embedded instance. To avoid all that coding stuff, here's a function, "immerse", that automatically sets as class properties all attributes that an instance of another class have, and that are not in the main class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | # helper descriptor
class _descr(object):
objrefs = {}
clsrefs = {}
def __init__(self,name):
self.name = name
def __get__(self,instance,owner):
if instance is None:
return getattr(_descr.clsrefs[id(owner)],self.name)
else:
return getattr(_descr.objrefs[id(instance)],self.name)
def __set__(self,instance,value):
setattr(_descr.objrefs[id(instance)],self.name,value)
# main function
def immerse(source_obj,dest_obj):
dest_cls = dest_obj.__class__
_descr.objrefs[id(dest_obj)]=source_obj
_descr.clsrefs[id(dest_cls)]=source_obj.__class__
for name in dir(source_obj):
if not hasattr(dest_obj,name):
setattr(dest_cls,name,_descr(name))
### TEST ###
# class whose instance will be immersed in B instances
class A:
x1 = "A.x1"
y1 = "A.y1"
def __init__(self):
self.x2 = "x2 of %s"%self
self.y2 = "y2 of %s"%self
def foo1(self,z):
print "A.foo1(%s,%s)"%(self,z)
def foo2(self,z):
print "A.foo2(%s,%s)"%(self,z)
def __getitem__(self,value):
print "A.__getitem__(%s,%s)"%(self,value)
return value
# main class
class B(object):
x1 = "B.x1"
def __init__(self):
self.y2 = "y2 of %s"%self
self.a = A() # instance to be immersed
immerse(self.a,self) # immersion
def foo1(self,z):
print "B.foo1(%s,%s)"%(self,z)
b=B()
print "b.x1="+b.x1
print "b.x2="+b.x2
print "b.y1="+b.y1
print "b.y2="+b.y2
print "executing b.foo1(10)..."
b.foo1(10)
print "executing b.foo2(20)..."
b.foo2(20)
print "executing b['hi all']..."
b["hi all"]
# output:
# b.x1=B.x1
# b.x2=x2 of <__main__.A instance at 0x00B85828>
# b.y1=A.y1
# b.y2=y2 of <__main__.B object at 0x00B83A50>
# executing b.foo1(10)...
# B.foo1(<__main__.B object at 0x00B83A50>,10)
# executing b.foo2(20)...
# A.foo2(<__main__.A instance at 0x00B85828>,20)
# executing b['hi all']...
# A.__getitem__(<__main__.A instance at 0x00B85828>,hi all)
|
There are other ways to solve this, but I found only code that use __getattr__ and __setattr__ : in that case we can't find the "immersed" attributes as proper attribute of our class: they aren't listed when we call dir(obj). Hope this help, enjoy! :-)