Welcome, guest | Sign In | My Account | Store | Cart

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.

Python, 80 lines
 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! :-)

Created by Diego Novella on Mon, 25 Apr 2005 (PSF)
Python recipes (4591)
Diego Novella's recipes (3)

Required Modules

  • (none specified)

Other Information and Tasks