I'm a python addict !

Paul McGuire ptmcg at austin.rr.com
Mon Jan 26 12:52:01 EST 2009


On Jan 26, 10:54 am, "J. Cliff Dyer" <j... at sdf.lonestar.org> wrote:
> On Fri, 2009-01-23 at 20:25 -0800, Paul McGuire wrote:
> > Want to change the type/behavior of an object from class A to class
> > B?  How about this:
>
> >     aobj = A()
> >     aobj.__class__ = B
>
> > Try *that* in as simple-looking C++ or Java!
>
> Wow.  That looks very powerful and fun.  But scary.  Any thoughts on how
> you would use that in a way that wouldn't unleash sulphurous code
> smells?
>

This technique is perfect for implementing the GoF State pattern.

In the State pattern, you implement behavior for an object's various
states using one of several interchangeable classes.  The classes are
"interchangeable" in that they all implement a common interface.  Here
is my favorite State pattern example, a traffic light:


import time

class TrafficLight(object):
    pass

class RedLight(TrafficLight):
    cars_can_go = False
    pedestrians_can_cross = True
    color = (255,0,0)
    duration = 20

class YellowLight(TrafficLight):
    cars_can_go = True
    pedestrians_can_cross = False
    color = (255,255,0)
    duration = 5

class GreenLight(TrafficLight):
    cars_can_go = True
    pedestrians_can_cross = False
    color = (0,255,0)
    duration = 15

# now add in next_state class vars for state transitions
RedLight.next_state = GreenLight
YellowLight.next_state = RedLight
GreenLight.next_state = YellowLight
TrafficLight.initial_state = RedLight

# run a traffic light for a while...
can_they = lambda cond : ("can't","can")[cond]
light = TrafficLight.initial_state()
while 1:
    print light.__class__.__name__
    print "waiting for", light.duration, "seconds"
    print "Cars", can_they(light.cars_can_go), "go"
    print "People", can_they(light.pedestrians_can_cross), "cross"
    print
    time.sleep(light.duration)

    # how you have to do it in C++ and Java
    # light = light.next_state()

    # using Python
    light.__class__ = light.next_state


Gives this output:

RedLight
waiting for 20 seconds
Cars can't go
People can cross

GreenLight
waiting for 15 seconds
Cars can go
People can't cross

YellowLight
waiting for 5 seconds
Cars can't go
People can't cross

RedLight
waiting for 20 seconds
Cars can't go
People can cross

... and so on ...



In Python, the base TrafficLight class isn't even necessary ("don't
need no stinking interfaces!"), although it is a good place to define
default behavior, and it helps tie together the other classes from a
self-documentation standpoint.  But any class that has the necessary
attributes would suffice, whether it inherits from TrafficLight or
not.

class HoldForEmergencyVehiclesLight(object):
    cars_can_go = False
    pedestrians_can_cross = False
    color = (255,0,0)


-- Paul




More information about the Python-list mailing list