ObjectA calling ObjectB

M

Midas

In my "main" code, I would like to create two
new objects (ObjectA and ObjectB) and have
ObjectA directly call an ObjectB method. In
order to do this I believe ObjectA must hold
a reference to ObjectB. What about the name
of the method? Must it be hardcoded in
ObjectA?
 
L

Lawrence Oluyede

In my "main" code, I would like to create two
new objects (ObjectA and ObjectB) and have
ObjectA directly call an ObjectB method. In
order to do this I believe ObjectA must hold
a reference to ObjectB. What about the name
of the method? Must it be hardcoded in
ObjectA?

You could simply do something like this:

class A:
def __init__(self):
self.ObjectB = B()

class B:
def someMethod(self):
pass

if __name__ == "__main__":
ObjectA = A()
ObjectA.ObjectB.someMethod()

HTH
 
M

Midas

Thanks for replying.
It looks like you hardcoded the name ObjectB within ClassA. I'd like to avoid all hardcoding of names. In other words, I'd like ObjectA to be *told*, at run time, which object to call and which method to call.
 
L

Lawrence Oluyede

Thanks for replying. It looks like you hardcoded the name ObjectB
within ClassA. I'd like to avoid all hardcoding of names. In other
words, I'd like ObjectA to be *told*, at run time, which object to call
and which method to call.

Mmm what do you mean with "to be told, at run time, which object
to call and which method to call" ?

Something like:

if var == "a":
# create object a and call method x
else:
# create object c and call method y

?
 
L

Lee Harr

Thanks for replying.
It looks like you hardcoded the name ObjectB within ClassA. I'd like to avoid all hardcoding of names. In other words, I'd like ObjectA to be *told*, at run time, which object to call and which method to call.



class A:
def __init__(self):
self.b = B()
def run_time(self, method_name):
getattr(self.b, method_name)()

class B:
def foo(self):
print 'foo!'

a = A()
a.run_time('foo')
 
M

Midas

By the way, thanks for assisting.

Here's my plan:

My main module would have three code sections:

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.

Midas
 
A

Alan Gauld

It looks like you hardcoded the name ObjectB within ClassA.
I'd like to avoid all hardcoding of names. In other words,
I'd like ObjectA to be *told*, at run time, which object
to call and which method to call.

While what you ask is possible it does kind of mess up the ideas
of good OO design. For this to happen the caller of A's methods
must know that A contains a B (not too bad but not pure OOD) and,
much worse, know that B contains a method called foo which it
tells A to call.

The law of demeter suggests you should create a method on A that
knows what to do, which may entail calling a method on B but it
may equally entail looking up a third object which is a message
dispatcher or ORB and getting it to do the work. The client of A
shouldn't really know how A's internals work.

So I guess I'm querying whether your design is as decoupled as it
should be. The only thing that should know what A has inside is
A... To do what you request something outside of A has to know
about B, give it to A then request A to call a known method of
the B givento A. Why not just have the external agency manage B
directly since it is already tightly coupled to it?

However I can equally guess that in the real world there may be
some cases, especially in data driven applications where you want
to dynamically control the internals of A, although even there
creating a dispather mechanism may be worth the extra work...

Alan G.
Author of the Learn to Program website
http://www.freenetpages.co.uk/hp/alan.gauld
 
M

Midas

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.
 
A

Alan Gauld

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.

Sounds like you need a list or dictionary full of objects.
Part 3) Call the first object, which calls another, etc. like an electrical circuit.

That's a pretty unusual electrical circuit, but I think I see
what you mean...

You want a calling sequence that can be changed. That could be
another list or dictionary mapping inputs to responses.
To change the circuit, I would only change part 2 and perhaps part 3.

In which case to change the circuit you only need to change the
calling sequences.
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

So far it looks more like a list of functions than a list of
objects.
ObjectX would call either, ObjectY.Input3 or ObjectZ.Input7,
because it was connected that way in part 2.

You can either hard code Object X or have object X hold the tewo
lists I mentioned above. When you intialise ObjectX you need to
pass in the data to populate the lists.

The other, arguabluy more OO solution, would be to have the
inputs as message objects which know which objects to call. Thus
when you pass the "TurnOnS" message it has embedded within it a
reference to ObjectY.Input3 and a method called doit() or
somesuch. Then when object X receives the message it performs
some sanity/security checks then X tells the message to doit().
Probably a better solution would be to have the message objects
hold the sequence information but ObjectX hold the objects. X
then applies the sequence to its own objects.

That way when a message needs a new sequence you make the change
to the message that is affected. This encapsulates the change in
a much more logical way.

Lots of possibilities. Few of them actually requiring that you
pass around object and method names explicitly.

Alan g.

Author of the Learn to Program website
http://www.freenetpages.co.uk/hp/alan.gauld
 
M

Miki Tebeka

Hello Midas,
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.
def __init__(self):
self.sisters = {}
def register(self, msg, func, *args):
self.sisters[msg] = (func, args)
def process(self, msg):
func, args = self.sisters[msg]
func(*args)

print msg

HTH.
Miki
 
P

Peter Otten

Midas said:
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
 
P

Peter Otten

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

Read: _manually_ ensure a consistent state for the given _example_. The
general case is definitely no toy problem.
Also, beware of loops in the wiring.

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,173
Messages
2,570,937
Members
47,481
Latest member
ElviraDoug

Latest Threads

Top