Help With Better Design

attn.steven.kuo at gmail.com attn.steven.kuo at gmail.com
Wed Jun 20 05:42:09 CEST 2007


On Jun 19, 6:34 pm, apolloni... at gmail.com wrote:
> Greetings,
>
> I have been working on a little project today to help me better
> understand classes in Python (I really like Python). I am a self
> taught programmer and consider myself to fall in the "beginner"
> category for sure. It was initially sparked by reading about "state
> machines". This was my attempt at it however I feel it is not quite
> where it should be:
>
> ON  = "ON"
> OFF = "OFF"
>
> class LightBulb:
>     def __init__(self, initial_state):
>         self.state = initial_state
>
>     def TurnOn(self):
>         if self.state == OFF:
>             self.state = ON
>         else:
>             print "The Bulb Is Already ON!"
>
>     def TurnOff(self):
>         if self.state == ON:
>             self.state = OFF
>         else:
>             print "The Bulb Is Aleady OFF!"
>
> if __name__== "__main__":
>     light = LightBulb(OFF)
>     simulation_running = True
>     while simulation_running:
>         print "The light is", light.state
>         print ""
>         print "Please choose an action:"
>         print ""
>         print "[1] Turn Light On"
>         print "[2] Turn Light Off"
>         print "[3] Exit Simulation"
>         print ""
>         u_choice = raw_input("Please Enter Your Choice: ")
>         if u_choice == '1':
>             light.TurnOn()
>         if u_choice == '2':
>             light.TurnOff()
>         elif u_choice == '3':
>             break
>         else:
>             continue
>
> The test portion of the code is actually longer than the class
> itself :-) I would like to be able to get a good hold of the concept
> with this example before I try to model a more complex problem. Would
> someone be willing to give me some feedback on this class and whether
> I am on the right track or how I might better go about it?



If all you're implementing is on-or-off logic, then
I'd use the boolean values in Python (True and False),
rather than defining my own 'ON' and 'OFF'.  Here
I use __str__ for printing and a _toggle function
to cut down on the possibility of coding errors:


class LightBulb:
    def __init__(self, bool):
        self.on = bool
    def __str__(self):
        return self.on and "On" or "Off"
    def _toggle(self):
        self.on = not self.on
    def TurnOn(self):
        if self.on: print "\tThe Bulb is ready %s" % self
        else: self._toggle()
    def TurnOff(self):
        if not self.on: print "\tThe Bulb is ready %s" % self
        else: self._toggle()

if __name__ == "__main__":
    light = LightBulb(False)
    while True:
        print """
        The light is %s

        Please choose an action:

        [1] Turn Light On
        [2] Turn Light Off
        [3] Exit
        """ % light
        u_choice = raw_input("Please Enter Your Choice: ")
        if u_choice == '1':
            light.TurnOn()
        elif u_choice == '2':
            light.TurnOff()
        elif u_choice == '3':
            break
        else:
            continue



If you're really coding a state machine
wherein many states are possible and many
choices are availble to the user, then I'd refactor.
Rather than having a long sequence of if ... elif ...
elif ... else, perhaps I'd use something like:


import sys

class LightBulb:
    def __init__(self, bool):
        self.on = bool
    def process_instruction(self, wanted):
        """ Pass self to unbound method """
        try:
            LightBulb.instructions[wanted][1](self)
        except IndexError:
            pass
    def __str__(self):
        return self.on and "On" or "Off"
    def _toggle(self):
        self.on = not self.on
    def TurnOn(self):
        if self.on: print "\n\t** The Bulb is already %s **" % self
        else: self._toggle()
    def TurnOff(self):
        if not self.on: print "\n\t** The Bulb is already %s **" %
self
        else: self._toggle()

    instructions = ( \
            ("Exit", sys.exit),
            ("Turn Light On", TurnOn),
            ("Turn Light Off", TurnOff),)

if __name__ == "__main__":
    light=LightBulb(False)
    usage=["\t%d: %s" % (i,t[0]) for i,t in
enumerate(LightBulb.instructions)]
    usage.insert(0, "\n\tThe light is %s\n\tPlease choose an action:")
    prompt = "\n".join(usage)

    while True:
        print prompt % light
        u_choice = raw_input("\nPlease Enter Your Choice: ")
        try:
            light.process_instruction(int(u_choice))
        except ValueError:
            pass



Note that I can add intructions as needed to
LightBulb.instructions and not have to change the
user interface.

--
Hope this helps,
Steven




More information about the Python-list mailing list