Marco Benvoglio
Marco Benvoglio

Reputation: 1363

Representing a Finite State Machine in Python Application Logic

The problem I'm trying to solve is-- I have a python application that accepts user input in a variety of ways and raises events based on those inputs. I am wanting to usE a finite state machine to handle the states transitions and currently have the graph of the finite state machine represented in the python code itself.

Here's what I've tried so far by implementing the equivalent of a big switch statement in python, like this:

if input == 0 and prev_state == 1:
    cur_state = 3
elif input == 1 and prev_state == 2:
    cur_state = 4

This is clumsy and error prone, so I'd like to move this graph definition of this outside of the python code and into a separate file that's using something like BNF, or similar, to make it easier to manage the finite state machine graph.

The fsm graph file might look something like this:

current_state == 1 and input == 2 -> next_state = 0

The python code might look something like this (psuedo):

fms = MyFsm("my_graph.txt")
while(True):
    input = console.get_input()
    current_state = fsm.transition(previous_state, input)

My question is: how can I represent a finite state machine in python without using a bunch of if / elif statements?

Upvotes: 1

Views: 2104

Answers (1)

Bill
Bill

Reputation: 1257

Yes, your gut feeling is correct that the if/else/switch approach to managing state is error prone. While it can be fine for smaller FSMs, they can grow unwieldy pretty quickly.

If you're input is a single value, then one simple approach for managing this in Python would be to use a dictionary to map current state and input to transition state. For example,

map = [
    { 'input': 0, 'current_state': 0, 'transition_state': 1 },
    { 'input': 0, 'current_state': 1, 'transition_state': 0 },
]

Then your state transition code would simply search for the right transition state based on the values of input and current_state. For example,

def lookup(input, state):
    transition_state = None
    for item in map:
        if item.current_state == state and item.input == input:
            transition_state = item.transition_state

    return transition_state

This is better than the if/elif approach since you're separating the FSM transitions from the python code itself, which then makes it possible and much easier to load the FSM dataset from an external file, database, etc.

Upvotes: 2

Related Questions