[Tutor] designing POOP

Alan Gauld alan.gauld at btinternet.com
Sat Feb 9 00:41:15 CET 2008


"bhaaluu" <bhaaluu at gmail.com> wrote

There have been lots of comments about this already but
I'm deliberately jumping in at this level because I want
to pick up a few general points...

> class Explorer(object):
>    """player"""
>    def __init__(self,name):
>        """initilaization method"""
>        self.__name = name
>        self.strength = 20
>        self.wealth = 60
>
>    def get_name(self):
>        return self.__name

Kent already pointed out this is not needed.

But as a general rule consider what I said earlier about
objects being based on behaviour. And that the data should
be there to support the behaviour.
So in this case ask:
Why do I have a name, strength and wealth?
What behaviour do these support?

Behaviour is expressed as methods so I am expecting to
see methods sof Explorer that use the attributes, otherwise
the Explorer is just a data container like a list or dictionary.

> class Light(object):
>    """light switch"""
>
>    def __init__(self,light):
>        self.light = light
>
>    def state(self):
>        if self.light == 0:
>            print (" IT IS TOO DARK TO SEE ANYTHING")
>        else:
>            print (" THE LIGHTS ARE ON, BUT NO ONE'S HOME")

You have a method here that reports the state but
doesn't a light switch usually do something?
Like turn the light on or off?
Usually by a toggle operation?
So maybe a toggle method would be good:

     def toggle(self):
         self.light == not self.light   # make it a boolean

Also remembering the principle that UI and logic should be
separated it might be good to pull the printing out of the
class and just let the method returmn the string. And as
Kent already suggested for Explorer that could be done
with an __str__ method so all you need do in the consumer
is:

print switch

> def cs():
>    print "\n"*50
>
> def main():
>    tally = 0
>    switch = Light(0) #instance
>    cs() # clear screen
>    name = raw_input(" WHAT IS YOUR NAME, EXPLORER? ")
>    explr = Explorer(name)
>    while True:
>        cs() # clear screen
>        print (" %s, YOUR STRENGTH IS %d" % (explr.get_name(), 
> explr.strength))
>        print (" YOU HAVE $%d" % explr.wealth)

Kent has addressed this specifically but as a general rule remember
the consumer should not have to get at the data attributes of an 
object.
You should only need to send messages to the Explorer, in this case
it's a status report - which we already said can be done via a __str__
method.

>        switch.state()
>        print
>        print
>        answer = raw_input(" WHAT DO YOU WANT TO DO? [Q|L]: ")
>        if answer.upper() == "Q":
>            break
>        if answer.upper() == "L":
>                if switch.light == 1:
>                    switch.light = 0
>                else:
>                    switch.light = 1

And here is the toggle method, except its in your program
rather than in the object. Let the object do it to itself, do not
try to mess with the data directly

           if answer.upper() == "L":
                     switch.toggle()

>                    explr.strength -= 5
>                    explr.wealth -= 15


Now I'm not quite sure why you decrease these but again
the Explorer should be doing it to himself - objects do it
to themselves. If the Explorer always loses strengty and
wealth after a turn then the method could be called
newTurn() or somesuch. But I suspect there might be
a more meaningful name we could use.


>                    if explr.wealth <= 0:
>                        print
>                        print (" YOU HAVE NO MONEY")
>                        time.sleep(1)
>                    if explr.strength <= 0:
>                        print
>                        print (" YOU DIED...")
>                        time.sleep(1)
>                        break

And all of this could be built into the explorer method above,
maybe implemented as an exception?

def newTiurn(self):
     self.wealth -= 15
     self.strength -= 5
     if self.wealth <= 0:
         raise ExplorerBroke
     if self.strength <= 0
         raise ExplorerDied

You control code then looks something like:

           if answer.upper() == "L":
                     switch.toggle()
                     try: explr.newTurn()
                     except ExplorerBroke e: print e.message
                     except ExplorerDied e: print e.message

Or with a bit more intelligence in the __str__ method

           if answer.upper() == "L":
                     switch.toggle()
                     try: explr.newTurn()
                     except ExplorerBroke,ExplorerDied:
                             print explr

Really the outside control code should be focused around
the user interaction and senmding messages to the objects.
It should not be pulling out data from inside the objects to
do anything with it, that is the job of the objects.

Occasionally we can break that rule if its just for printing
or maybe to assign directly to another value. For example
you could directly access switch.light if you needed to
pass that into a method of explorer

explr.reactToLight(switch.light)

But even there its better to pass the switch to the explorer
and let him test the switch state inside the method.

HTH,

-- 
Alan Gauld
Author of the Learn to Program web site
http://www.freenetpages.co.uk/hp/alan.gauld 




More information about the Tutor mailing list