Help With Better Design

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Tue Jun 19 23:44:52 EDT 2007


En Tue, 19 Jun 2007 22:34:27 -0300, <apollonius2 at gmail.com> escribió:

> 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:

That's rather good as it is!

> 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!"

One could argue here: is it an error to attempt to turn the light on  
again, if it is already on?
If yes: raising an exception is the usual way to report error conditions  
(let the caller handle it, if he cares enough)
If not: why to check the current state? Just set the new state as ON,  
whatever was the prior state.
The same for TurnOff. (BTW, the reccomended style is to use lower_case  
(best) or mixedCase for method names: turn_on or turnOn)

>     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 :-)

That's often the case!

> 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?

The example is fine. You could move on from "interactive testing" (your  
"demo" program, where a human runs some code, more-or-less at random, sees  
the results and judges by himself if it is "OK" or "wrong") into  
"automated unit testing": an automated sequence of tests, each with its  
input and expected output, that can be executed automatically and without  
any human intervention.

There is a framework for writing those (see the unittest module), but you  
can start just by using the assert statement:

light = LightBulb(OFF)
assert light.state == OFF # ensure that it gets initialized correctly
light.TurnOn()
assert light.state == ON # ensure that TurnOn actually does as intended
light.TurnOff()
assert light.state == OFF
light.TurnOff()
assert light.state == OFF # an attempt to turn it off again should leave  
it off
light.TurnOn()
light.TurnOn()            # an attempt to turn it on again
assert light.state == ON
# some more tests
light = LightBulb(ON)
assert light.state == ON # should test both initial states
light = LightBulb(0) # what should happen here?
light.TurnOn()
assert light.state == ON  # oops!
light.TurnOff()
assert light.state == OFF  # oops!

This has many advantages: you can write the tests carefully once and run  
many times later, and detect breakages; you can't take a "likely" answer  
for a "true" answer; etc.

-- 
Gabriel Genellina




More information about the Python-list mailing list