Python state-machine design Python state-machine design python python

Python state-machine design


I don't really get the question. The State Design pattern is pretty clear. See the Design Patterns book.

class SuperState( object ):    def someStatefulMethod( self ):        raise NotImplementedError()    def transitionRule( self, input ):        raise NotImplementedError()class SomeState( SuperState ):    def someStatefulMethod( self ):        actually do something()    def transitionRule( self, input ):        return NextState()

That's pretty common boilerplate, used in Java, C++, Python (and I'm sure other languages, also).

If your state transition rules happen to be trivial, there are some optimizations to push the transition rule itself into the superclass.

Note that we need to have forward references, so we refer to classes by name, and use eval to translate a class name to an actual class. The alternative is to make the transition rules instance variables instead of class variables and then create the instances after all the classes are defined.

class State( object ):    def transitionRule( self, input ):        return eval(self.map[input])()class S1( State ):     map = { "input": "S2", "other": "S3" }    pass # Overrides to state-specific methodsclass S2( State ):    map = { "foo": "S1", "bar": "S2" }class S3( State ):    map = { "quux": "S1" }

In some cases, your event isn't as simple as testing objects for equality, so a more general transition rule is to use a proper list of function-object pairs.

class State( object ):    def transitionRule( self, input ):        next_states = [ s for f,s in self.map if f(input)  ]        assert len(next_states) >= 1, "faulty transition rule"        return eval(next_states[0])()class S1( State ):    map = [ (lambda x: x == "input", "S2"), (lambda x: x == "other", "S3" ) ]class S2( State ):    map = [ (lambda x: "bar" <= x <= "foo", "S3"), (lambda x: True, "S1") ]

Since the rules are evaluated sequentially, this allows a "default" rule.


In the April, 2009 issue of Python Magazine, I wrote an article on embedding a State DSL within Python, using pyparsing and imputil. This code would allow you to write the module trafficLight.pystate:

# trafficLight.pystate# define state machinestatemachine TrafficLight:    Red -> Green    Green -> Yellow    Yellow -> Red# define some class level constantsRed.carsCanGo = FalseYellow.carsCanGo = TrueGreen.carsCanGo = TrueRed.delay = wait(20)Yellow.delay = wait(3)Green.delay = wait(15)

and the DSL compiler would create all the necessary TrafficLight, Red, Yellow, and Green classes, and the proper state transition methods. Code could call these classes using something like this:

import statemachineimport trafficLighttl = trafficLight.Red()for i in range(6):    print tl, "GO" if tl.carsCanGo else "STOP"    tl.delay()    tl = tl.next_state()

(Unfortunately, imputil has been dropped in Python 3.)


There is this design pattern for using decorators to implement state machines. From the description on the page:

Decorators are used to specify which methods are the event handlers for the class.

There is example code on the page as well (it is quite long so I won't paste it here).