On Mon, 2009-01-26 at 09:52 -0800, Paul McGuire wrote: > On Jan 26, 10:54 am, "J. Cliff Dyer" <j...@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 >
Thanks. That makes sense. But your example creates a new instance of the new class each time, rather than changing the class of a persistent instance, as the original example, to which I was responding, did. But perhaps something like: class TrafficLight(object): def change_light(self): self.__class__ = next_state and then you can persist information about the light (bulb_type in set(['led', 'incandescent']), last_maintenance_date, location, etc.) on the instance level, unaffected by the changing color. Interesting stuff. Cheers, Cliff -- http://mail.python.org/mailman/listinfo/python-list