ObjectA calling ObjectB

Peter Otten __peter__ at web.de
Sun Dec 28 15:13:45 CET 2003


Midas wrote:

> Thanks for assisting.
> 
> What I'm trying to do is as follows:
> 
> Part 1)  Create 10 new assorted objects
> Part 2)  Link up the objects, somehow, so they can communicate with each
> other directly, like parts of an electrical circuit.
> Part 3)  Call the first object, which calls another, etc. like an
> electrical circuit.
> 
> To change the circuit, I would only change part 2 and perhaps part 3.
> 
> For example, ObjectX could have an input, for a string, and two outputs.
> If the input is "TurnOnS", it calls ObjectY.Input3
> If the input is "TurnOnT", it calls ObjectZ.Input7
> 
> ObjectX would call either, ObjectY.Input3 or ObjectZ.Input7, because it
> was connected that way in part 2.
> 
> I could then later change part 2 so ObjectX called either ObjectE.Input2
> or ObjectF.Input9 In other words, I could "re-wire" the circuit without
> changing anything in the objects.

I think what you want is the observer pattern that is widely used, e. g. for
wiring the Java Swing GUI with the underlying data model.

Below is a toy example that connects some logical components. Rather than
invoking different methods on a per class basis, I store object references
directly and introduce a common interface for all classes, i. e. the
notify() method. As always in Python, the common base class is not a
necessity to make the compiler happy, but a means to reduce redundant code.

<demo.py>
class Gadget(object):
    def __init__(self, name=None):
        self._state = False
        self.outputs = []
        self.inputs = []
        self.name = name
    def addinputs(self, *inputs):
        for i in inputs:
            self.addinput(i)
    def addoutput(self, o):
        self.outputs.append(o)
        o.inputs.append(self)
    def addinput(self, i):
        self.inputs.append(i)
        i.outputs.append(self)
    def addoutputs(self, *outputs):
        for o in outputs:
            self.addoutput(o)
    def setstate(self, state):
        if self._state != state:
            self._state = state
            self.changed()
    def getstate(self):
        return self._state
    state = property(getstate, setstate)
    def changed(self):
        for o in self.outputs:
            o.notify(self)

class Not(Gadget):
    def notify(self, sender):
        self.state = not sender.state

class And(Gadget):
    def notify(self, sender):
        for i in self.inputs:
            if not i.state:
                self.state = False
                break
        else:
            self.state = True

class Or(Gadget):
    def notify(self, sender):
        for i in self.inputs:
            if i.state:
                self.state = True
                break
        else:
            self.state = False

class Input(Gadget):
    def __str__(self):
        return "\t%s is now %s" % (self.name, {False: "Off", True:
"On"}[self.state])

class Output(Input):
    def changed(self):
        print str(self)
    def notify(self, sender):
        self.state = sender.state

if __name__ == "__main__":
    def state(v):
        if v: return True
        else: return False
    def printState():
        for g in ("Input:", ione, itwo, ithree, "Output:", red, green,
blue):
            print g
    one, two, three = False, False, False

    # define the model
    ione, itwo, ithree = [Input(name) for name in "one two three".split()]
    gnot = Not()
    gor = Or()
    gand = And()
    gnot.addinputs(ione)
    gand.addinputs(gnot, itwo)
    gor.addinputs(ione, itwo, ithree)

    red, green, blue = [Output(name) for name in "red green blue".split()]
    gor.addoutput(red) # one or two or three
    gand.addoutput(green) # two and (not one)
    gnot.addoutput(blue) # not one

    #play with it
    print "set one, two, three to True or False, e. g."
    print "one=True"
    print "type '?' to print the current state, 'quit' to quit"
    while True:
        cmd = raw_input()
        if cmd == "quit":
            break
        elif cmd in ("?", "print"):
            printState()
        else:
            try:
                exec cmd
            except:
                pass
            else:
                ione.state = state(one)
                itwo.state = state(two)
                ithree.state = state(three)
</demo.py>

And now a sample session (note that I didn't bother to ensure a consistent
initial state):

<session>
set one, two, three to True or False, e. g.
one=True
type '?' to print the current state, 'quit' to quit
?
Input:
        one is now Off
        two is now Off
        three is now Off
Output:
        red is now Off
        green is now Off
        blue is now Off
one=1
        red is now On
two=1
three=1
one=two=three=0
        green is now On
        blue is now On
        green is now Off
        red is now Off
two=1
        green is now On
        red is now On
quit
</session>

Peter






More information about the Python-list mailing list