I recently came across this code on the internet and I'm having a very hard time understand how it works. I was hoping someone could comment the code a bit in order to help me learn it better? I understand most of it, but get lost when any of the code deals with the "handler" parts. (ie. why does the author feed multiple "handlers" into a dictionary?) Anyway here it is:

class StateMachine:
    def __init__(self):
        self.handlers = {}
        self.endStates = []
        self.startState = None

    def add_state(self, name, handler, end_state=0):
        self.handlers[name] = handler
        if end_state:
            self.endStates.append(name)

    def set_start(self, name):
        self.startState = name

    def run(self, content):
        if self.startState in self.handlers:
            handler = self.handlers[self.startState]
        else:
            raise "InitializationError", ".set_start() has to be called before .run()"
        if not self.endStates:
            raise  "InitializationError", "at least one state must be an end_state"

        oldState = self.startState
        while 1:
            (newState, content) = handler(content, oldState)
            if newState in self.endStates:
                print "reached ", newState, "which is an end state"
                break 
            else:
                handler = self.handlers[newState]
            oldState = newState




from statemachine import StateMachine

positive_adjectives = ["great","super", "fun", "entertaining", "easy"]
negative_adjectives = ["boring", "difficult", "ugly", "bad"]

def transitions(txt, state):
    splitted_txt = txt.split(None,1)
    word, txt = splitted_txt if len(splitted_txt) > 1 else (txt,"")
    if state == "Start":
        if word == "Python":
            newState = "Python_state"
        else:
            newState = "error_state"
        return (newState, txt)
    elif state == "Python_state":
        if word == "is":
            newState = "is_state"
        else:
            newState = "error_state"
        return (newState, txt) 
    elif state == "is_state":
        if word == "not":
            newState = "not_state"
        elif word in positive_adjectives:
            newState = "pos_state"
        elif word in negative_adjectives:
            newState = "neg_state"
        else:
            newState = "error_state"
        return (newState, txt)
    elif state == "not_state":
        if word in positive_adjectives:
            newState = "neg_state"
        elif word in negative_adjectives:
            newState = "pos_state"
        else:
            newState = "error_state"
        return (newState, txt)


if __name__== "__main__":
    m = StateMachine()
    m.add_state("Start", transitions)
    m.add_state("Python_state", transitions)
    m.add_state("is_state", transitions)
    m.add_state("not_state", transitions)
    m.add_state("neg_state", None, end_state=1)
    m.add_state("pos_state", None, end_state=1)
    m.add_state("error_state", None, end_state=1)
    m.set_start("Start")
    m.run("Python is great")
    m.run("Python is difficult")
    m.run("Perl is ugly")

No, the diagram only shows what the code is supposed to accomplish, not how it is accomplishing it. My question is really about how the Statemachine class is interacting with the transitions function.

How about adding some print statements:

def run(self, content):
    if self.startState in self.handlers:
        handler = self.handlers[self.startState]
    else:
        raise "InitializationError", ".set_start() has to be called before .run()"
    if not self.endStates:
        raise  "InitializationError", "at least one state must be an end_state"

    oldState = self.startState
    print
    while 1:
        print content, oldState,
        (newState, content) = handler(content, oldState)
        print '->',newState
        if newState in self.endStates:
            print "reached ", newState, "which is an end state"
            break 
        else:
            handler = self.handlers[newState]
        oldState = newState

There is many packages in pypi
http://pypi.python.org/pypi?%3Aaction=search&term=state+machine+python&submit=search

http://pypi.python.org/pypi/pytomaton/1.1.1 looks nice for me.

Edited 4 Years Ago by pyTony

What it comes down to is that each state transition can have it's own behavior, represented by a function. In this case, all of the states use the same function to handle the different states, but that is just to keep the code simpler; in practice, you would probably have one function for each state transition.

You may want to compare this to another FSM design which I came up with for a compiler class some years ago. It is also in Python, and while the two have some striking similarities, they also have significant differences as well.

Edited 4 Years Ago by Schol-R-LEA: Added link to another FSM example.

@Schol-R-LEA :
Thank you for your VERY well commented FSM code! It is much easier to follow. The only thing i'd ask right now is if you have a very simple sample program that uses these classes so that i can try it and watch things work? Thanks again in advance!

This article has been dead for over six months. Start a new discussion instead.