<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://performiq.com/kb/index.php?action=history&amp;feed=atom&amp;title=Python_Finite_State_Machine_Example</id>
	<title>Python Finite State Machine Example - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://performiq.com/kb/index.php?action=history&amp;feed=atom&amp;title=Python_Finite_State_Machine_Example"/>
	<link rel="alternate" type="text/html" href="https://performiq.com/kb/index.php?title=Python_Finite_State_Machine_Example&amp;action=history"/>
	<updated>2026-05-18T13:48:39Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>https://performiq.com/kb/index.php?title=Python_Finite_State_Machine_Example&amp;diff=2155&amp;oldid=prev</id>
		<title>PeterHarding: New page: &lt;pre&gt; #!/usr/bin/env python &#039;&#039;&#039;This module implements a Finite State Machine (FSM). In addition to state this FSM also maintains a user defined &quot;something&quot;. This &quot;something&quot; is effectively...</title>
		<link rel="alternate" type="text/html" href="https://performiq.com/kb/index.php?title=Python_Finite_State_Machine_Example&amp;diff=2155&amp;oldid=prev"/>
		<updated>2008-05-24T07:15:17Z</updated>

		<summary type="html">&lt;p&gt;New page: &amp;lt;pre&amp;gt; #!/usr/bin/env python &amp;#039;&amp;#039;&amp;#039;This module implements a Finite State Machine (FSM). In addition to state this FSM also maintains a user defined &amp;quot;something&amp;quot;. This &amp;quot;something&amp;quot; is effectively...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;This module implements a Finite State Machine (FSM).&lt;br /&gt;
In addition to state this FSM also maintains a user defined &amp;quot;something&amp;quot;.&lt;br /&gt;
This &amp;quot;something&amp;quot; is effectively memory, so this FSM could be considered&lt;br /&gt;
a Push-down Automata (PDA) since a PDA is a FSM + memory.&lt;br /&gt;
&lt;br /&gt;
The following describes how the FSM works, but you will probably also need&lt;br /&gt;
to see the example function to understand how the FSM is used in practice.&lt;br /&gt;
&lt;br /&gt;
You define an FSM by building tables of transitions.&lt;br /&gt;
For a given input symbol the process() method uses these tables &lt;br /&gt;
to decide what action to call and what the next state will be. &lt;br /&gt;
The FSM has a table of transitions that associate:&lt;br /&gt;
        (input_symbol, current_state) --&amp;gt; (action, next_state)&lt;br /&gt;
where &amp;quot;action&amp;quot; is a function you define. The symbols and states &lt;br /&gt;
can be any objects. You use the add_transition() and add_transition_list() &lt;br /&gt;
methods to add to the transition table. The FSM also has a table&lt;br /&gt;
of transitions that associate:&lt;br /&gt;
        (current_state) --&amp;gt; (action, next_state)&lt;br /&gt;
You use the add_transition_any() method to add to this transition table.&lt;br /&gt;
The FSM also has one default transition that is not associated&lt;br /&gt;
with any specific input_symbol or state. You use the &lt;br /&gt;
set_default_transition() method to set the default transition.&lt;br /&gt;
&lt;br /&gt;
When an action function is called it is passed a reference to the FSM.&lt;br /&gt;
The action function may then access attributes of the FSM such as&lt;br /&gt;
input_symbol, current_state, or &amp;quot;something&amp;quot;. The &amp;quot;something&amp;quot; attribute &lt;br /&gt;
can be any object that you want to pass along to the action functions.&lt;br /&gt;
It is not used by the FSM. For parsing you would typically pass a list &lt;br /&gt;
to be used as a stack.&lt;br /&gt;
&lt;br /&gt;
The processing sequence is as follows.&lt;br /&gt;
The process() method is given an input_symbol to process.&lt;br /&gt;
The FSM will search the table of transitions that associate:&lt;br /&gt;
        (input_symbol, current_state) --&amp;gt; (action, next_state) &lt;br /&gt;
If the pair (input_symbol, current_state) is found then &lt;br /&gt;
process() will call the associated action function and then set the &lt;br /&gt;
current state to the next_state.&lt;br /&gt;
&lt;br /&gt;
If the FSM cannot find a match for (input_symbol, current_state)&lt;br /&gt;
it will then search the table of transitions that associate:&lt;br /&gt;
        (current_state) --&amp;gt; (action, next_state)&lt;br /&gt;
If the current_state is found then the process() method will call &lt;br /&gt;
the associated action function and then set the current state to &lt;br /&gt;
the next_state. Notice that this table lacks an input_symbol. &lt;br /&gt;
It lets you define transitions for a current_state and ANY input_symbol.&lt;br /&gt;
Hence, it is called the &amp;quot;any&amp;quot; table. Remember, it is always checked&lt;br /&gt;
after first searching the table for a specific (input_symbol, current_state).&lt;br /&gt;
&lt;br /&gt;
For the case where the FSM did not match either of the previous two cases&lt;br /&gt;
the FSM will try to use the default transition. If the default transition&lt;br /&gt;
is defined then the process() method will call the associated action function&lt;br /&gt;
and then set the current state to the next_state. This lets you define &lt;br /&gt;
a default transition as a catch-all case. You can think of it as an &lt;br /&gt;
exception handler. There can be only one default transition.&lt;br /&gt;
&lt;br /&gt;
Finally, if none of the previous cases are defined for an input_symbol &lt;br /&gt;
and current_state then the FSM will raise an exception. &lt;br /&gt;
This may be desirable, but you can always prevent this just by &lt;br /&gt;
defining a default transition.&lt;br /&gt;
&lt;br /&gt;
Noah Spurrier 20020822&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
class ExceptionFSM(Exception):&lt;br /&gt;
    &amp;#039;&amp;#039;&amp;#039;This is the FSM Exception class.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
    def __init__(self, value):&lt;br /&gt;
        self.value = value&lt;br /&gt;
    def __str__(self):&lt;br /&gt;
        return `self.value`&lt;br /&gt;
&lt;br /&gt;
class FSM:&lt;br /&gt;
    &amp;#039;&amp;#039;&amp;#039;This is a Finite State Machine (FSM).&lt;br /&gt;
    &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, initial_state, something):&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;This creates the FSM. &lt;br /&gt;
        You set the initial state here. The &amp;quot;something&amp;quot; attribute is any&lt;br /&gt;
        object that you want to pass along to the action functions.&lt;br /&gt;
        It is not used by the FSM. For parsing you would typically pass &lt;br /&gt;
        a list to be used as a stack.&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
        # Map (input_symbol, current_state) --&amp;gt; (action, next_state).&lt;br /&gt;
        self.state_transitions = {}&lt;br /&gt;
        # Map (current_state) --&amp;gt; (action, next_state).&lt;br /&gt;
        self.state_transitions_any = {}&lt;br /&gt;
        self.default_transition = None&lt;br /&gt;
        &lt;br /&gt;
        self.input_symbol = None&lt;br /&gt;
        self.initial_state = initial_state&lt;br /&gt;
        self.current_state = self.initial_state&lt;br /&gt;
        self.something = something&lt;br /&gt;
&lt;br /&gt;
    def reset (self):&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;This sets the current_state to the initial_state and&lt;br /&gt;
        sets input_symbol to None.&lt;br /&gt;
        The initial state was set by the constructor __init__().&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
        self.current_state = self.initial_state&lt;br /&gt;
        self.input_symbol = None&lt;br /&gt;
&lt;br /&gt;
    def add_transition (self, input_symbol, state, action, next_state):&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;This adds a transition that associates&lt;br /&gt;
                (input_symbol, current_state) --&amp;gt; (action, next_state)&lt;br /&gt;
        The action may be set to None in which case the process() method &lt;br /&gt;
        will ignore the action and only set the next_state.&lt;br /&gt;
           &lt;br /&gt;
        You can also set transitions for a list of symbols by using&lt;br /&gt;
        add_transition_list().&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
        self.state_transitions[(input_symbol, state)] = (action, next_state)&lt;br /&gt;
&lt;br /&gt;
    def add_transition_list (self, list_input_symbols, state, action, next_state):&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;This adds the same transition for lots of different input symbols.&lt;br /&gt;
        You can pass a list or a string. Note that it is handy to use&lt;br /&gt;
        string.digits, string.whitespace, string.letters, etc. to add&lt;br /&gt;
        transitions that match character classes.&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
        for input_symbol in list_input_symbols:&lt;br /&gt;
            self.add_transition (input_symbol, state, action, next_state)&lt;br /&gt;
&lt;br /&gt;
    def add_transition_any (self, state, action, next_state):&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;This adds a transition that associates&lt;br /&gt;
                (current_state) --&amp;gt; (action, next_state)&lt;br /&gt;
        The process() method checks these associations if it cannot&lt;br /&gt;
        first find a match of an (input_symbol, current_state).&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
        self.state_transitions_any [state] = (action, next_state)&lt;br /&gt;
&lt;br /&gt;
    def set_default_transition (self, action, next_state):&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;This sets the default transition. &lt;br /&gt;
        This defines an action and next_state if the FSM cannot find the&lt;br /&gt;
        input symbol and the current state in the transition list and &lt;br /&gt;
        if the FSM cannot find the current_state in the transition_any list.&lt;br /&gt;
        This is useful for catching errors and undefined states. &lt;br /&gt;
&lt;br /&gt;
        The default transition can be removed by setting the attribute&lt;br /&gt;
        default_transition to None.&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
        self.default_transition = (action, next_state)&lt;br /&gt;
&lt;br /&gt;
    def get_transition (self, input_symbol, state):&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;This returns (action, next state) given an input_symbol and state.&lt;br /&gt;
        This leaves the FSM unchanged. This does not update the current state &lt;br /&gt;
        nor does it trigger the output action. Normally you do not call &lt;br /&gt;
        this method. It is called by process().&lt;br /&gt;
        &lt;br /&gt;
        The sequence of steps to check for a defined transition goes from &lt;br /&gt;
        the most specific to the least specific. &lt;br /&gt;
        1. Check state_transitions[] that match (input_symbol, state)&lt;br /&gt;
        2. Check state_transitions_any[] that match (state)&lt;br /&gt;
           In other words, match a specific state and ANY input_symbol.&lt;br /&gt;
        3. Check if the default_transition is defined.&lt;br /&gt;
           This catches any input_symbol and any state.&lt;br /&gt;
           This is a handler for errors, undefined states, or defaults.&lt;br /&gt;
        4. No transition was defined. If we get here then raise an exception.&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
        if self.state_transitions.has_key((input_symbol, self.current_state)):&lt;br /&gt;
            return self.state_transitions[(input_symbol, self.current_state)]&lt;br /&gt;
        elif self.state_transitions_any.has_key (self.current_state):&lt;br /&gt;
            return self.state_transitions_any[self.current_state]&lt;br /&gt;
        elif self.default_transition != None:&lt;br /&gt;
            return self.default_transition&lt;br /&gt;
        else:&lt;br /&gt;
            raise ExceptionFSM (&amp;#039;Transition is undefined: (%s, %s).&amp;#039; % &lt;br /&gt;
                (str(input_symbol), str(self.current_state)) )&lt;br /&gt;
&lt;br /&gt;
    def process (self, input_symbol):&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;This is the main method that you call to process input.&lt;br /&gt;
        This may cause the FSM to change state and call an action.&lt;br /&gt;
        This method calls get_transition() to find the action and next_state&lt;br /&gt;
        associated with the input_symbol and current_state.&lt;br /&gt;
        If the action is None then the action is not called and&lt;br /&gt;
        only the current state is changed.&lt;br /&gt;
        This method processes one input symbol. You can process a list of&lt;br /&gt;
        symbols (or a string) by calling process_list().&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
        self.input_symbol = input_symbol&lt;br /&gt;
        (action, next_state) = self.get_transition (self.input_symbol, self.current_state)&lt;br /&gt;
        if action != None:&lt;br /&gt;
            action (self)&lt;br /&gt;
        self.current_state = next_state&lt;br /&gt;
&lt;br /&gt;
    def process_list (self, s):&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;This takes a list and sends each element to process().&lt;br /&gt;
        The list may be a string.&lt;br /&gt;
        &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
        for c in s:&lt;br /&gt;
            self.process (c)&lt;br /&gt;
&lt;br /&gt;
##########################################################################&lt;br /&gt;
# The following example demonstrates the use of the FSM class in &lt;br /&gt;
# processing RPN expressions. Run this module from the command line.&lt;br /&gt;
# You will get a prompt &amp;gt; for input. &lt;br /&gt;
# Enter an RPN Expression.&lt;br /&gt;
# Numbers may be integers. Operators are * / + -&lt;br /&gt;
# Use the = sign to evaluate and print the expression.&lt;br /&gt;
# For example: &lt;br /&gt;
#    167 3 2 2 * * * 1 - =&lt;br /&gt;
# will print:&lt;br /&gt;
#    2003&lt;br /&gt;
##########################################################################&lt;br /&gt;
&lt;br /&gt;
import string&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# These define the actions. &lt;br /&gt;
# Note that &amp;quot;something&amp;quot; is a list being used as a stack.&lt;br /&gt;
#&lt;br /&gt;
def BeginBuildNumber (fsm):&lt;br /&gt;
    fsm.something.append (fsm.input_symbol)&lt;br /&gt;
def BuildNumber (fsm):&lt;br /&gt;
    s = fsm.something.pop ()&lt;br /&gt;
    s = s + fsm.input_symbol&lt;br /&gt;
    fsm.something.append (s)&lt;br /&gt;
def EndBuildNumber (fsm):&lt;br /&gt;
    s = fsm.something.pop ()&lt;br /&gt;
    fsm.something.append (int(s))&lt;br /&gt;
def DoOperator (fsm):   &lt;br /&gt;
    ar = fsm.something.pop()&lt;br /&gt;
    al = fsm.something.pop()&lt;br /&gt;
    if fsm.input_symbol == &amp;#039;+&amp;#039;:&lt;br /&gt;
        fsm.something.append (al + ar)&lt;br /&gt;
    elif fsm.input_symbol == &amp;#039;-&amp;#039;:&lt;br /&gt;
        fsm.something.append (al - ar)&lt;br /&gt;
    elif fsm.input_symbol == &amp;#039;*&amp;#039;:&lt;br /&gt;
        fsm.something.append (al * ar)&lt;br /&gt;
    elif fsm.input_symbol == &amp;#039;/&amp;#039;:&lt;br /&gt;
        fsm.something.append (al / ar)&lt;br /&gt;
def DoEqual (fsm):&lt;br /&gt;
    print str(fsm.something.pop())&lt;br /&gt;
def Error (fsm):&lt;br /&gt;
    print &amp;#039;That does not compute.&amp;#039;&lt;br /&gt;
    print str(fsm.input_symbol)&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# This is where the example starts and the FSM state transitions are defined.&lt;br /&gt;
# Note that states (such as &amp;#039;INIT&amp;#039;) are strings. This is not necessary, but&lt;br /&gt;
# it makes the example easier to read.&lt;br /&gt;
#&lt;br /&gt;
def example ():&lt;br /&gt;
    f = FSM (&amp;#039;INIT&amp;#039;, []) # &amp;quot;something&amp;quot; will be used as a stack.&lt;br /&gt;
    f.set_default_transition (Error, &amp;#039;INIT&amp;#039;)&lt;br /&gt;
    f.add_transition_any  (&amp;#039;INIT&amp;#039;, None, &amp;#039;INIT&amp;#039;)&lt;br /&gt;
    f.add_transition      (&amp;#039;=&amp;#039;,               &amp;#039;INIT&amp;#039;,            DoEqual,          &amp;#039;INIT&amp;#039;)&lt;br /&gt;
    f.add_transition_list (string.digits,     &amp;#039;INIT&amp;#039;,            BeginBuildNumber, &amp;#039;BUILDING_NUMBER&amp;#039;)&lt;br /&gt;
    f.add_transition_list (string.digits,     &amp;#039;BUILDING_NUMBER&amp;#039;, BuildNumber,      &amp;#039;BUILDING_NUMBER&amp;#039;)&lt;br /&gt;
    f.add_transition_list (string.whitespace, &amp;#039;BUILDING_NUMBER&amp;#039;, EndBuildNumber,   &amp;#039;INIT&amp;#039;)&lt;br /&gt;
    f.add_transition_list (&amp;#039;+-*/&amp;#039;,            &amp;#039;INIT&amp;#039;,            DoOperator,       &amp;#039;INIT&amp;#039;)&lt;br /&gt;
    &lt;br /&gt;
    print&lt;br /&gt;
    print &amp;#039;Enter an RPN Expression.&amp;#039;&lt;br /&gt;
    print &amp;#039;Numbers may be integers. Operators are * / + -&amp;#039;&lt;br /&gt;
    print &amp;#039;Use the = sign to evaluate and print the expression.&amp;#039;&lt;br /&gt;
    print &amp;#039;For example: &amp;#039;&lt;br /&gt;
    print &amp;#039;    167 3 2 2 * * * 1 - =&amp;#039;&lt;br /&gt;
    inputs = raw_input (&amp;#039;&amp;gt;&amp;#039;)&lt;br /&gt;
    for s in inputs:&lt;br /&gt;
        f.process (s)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;#039;__main__&amp;#039;:&lt;br /&gt;
    example ()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Python]]&lt;/div&gt;</summary>
		<author><name>PeterHarding</name></author>
	</entry>
</feed>