xbe.at

Python / OOP and design patterns

Introduction to Finite State Machines in Python

4 min read, 2 sections

Introduction to Finite State Machines (FSMs) A Finite State Machine (FSM) is a computational model used to design systems that can be in one of a finite number of states. It transitions from one state to another based on specific inputs or events. FSMs are widely used in various domains, including computer science, electronics, and linguistics.

Components of an FSM An FSM consists of the following components:

  1. States: The different conditions or situations the system can be in.
  2. Transitions: The rules that define how the system moves from one state to another.
  3. Start State: The initial state of the system when it begins operation.
  4. Accept/Final States: The states that indicate successful completion of a task or sequence.

Simple FSM Example Let's start with a simple example of an FSM that models a turnstile system.

from enum import Enum

class State(Enum):
    LOCKED = 0
    UNLOCKED = 1

class TurnstileFSM:
    def __init__(self):
        self.state = State.LOCKED

    def coin_inserted(self):
        if self.state == State.LOCKED:
            self.state = State.UNLOCKED
            print("Turnstile unlocked.")
        else:
            print("Turnstile already unlocked.")

    def person_passed(self):
        if self.state == State.UNLOCKED:
            self.state = State.LOCKED
            print("Turnstile locked.")
        else:
            print("Turnstile is locked.")

Using the Turnstile FSM Here's how you can use the TurnstileFS M:

turnstile = TurnstileFS M()
turnstile.coin_inserted() # Output: Turnstile unlocked.
turnstile.person_passed() # Output: Turnstile locked.
turnstile.person_passed() # Output: Turnstile is locked.

Advantages of FSMs FSMs offer several advantages:

  • Simplicity: FSMs are easy to understand and implement.
  • Modular design: FSMs can be combined and composed to create more complex systems.
  • Deterministic behavior: Given a specific input, an FSM will always transition to a well-defined state.
  • Testing and verification: FSMs can be thoroughly tested and verified due to their finite nature.

Implementing FSMs in Python Python provides several ways to implement FSMs. One approach is to use classes and methods to represent states and transitions. Another approach is to use dictionaries or lookup tables to define state transitions.

Class-based FSM Implementation Here's an example of a class-based FSM implementation for a simple vending machine:

class State:
    def run(self):
        pass

class IdleState(State):
    def run(self):
        print("Waiting for input...")

class CoinInsertedState(State):
    def run(self):
        print("Coin inserted, select item...")

class ItemDeliveredState(State):
    def run(self):
        print("Item delivered, thank you!")

class VendingMachine:
    def __init__(self):
        self.state = IdleState()

    def coin_inserted(self):
        self.state = CoinInsertedState()

    def item_selected(self):
        self.state = ItemDeliveredState()
        self.dispense_item()

    def dispense_item(self):
        print("Dispensing item...")

    def run(self):
        while True:
            self.state.run()
            input_value = input("Enter input: ")
            if input_value == "coin":
                self.coin_inserted()
            elif input_value == "select":
                self.item_selected()

Using the Vending Machine FSM Here's how you can use the VendingMachine FSM:

vending_machine = VendingMachine()
vending_machine.run()

Input:

Enter input: coin
Enter input: select

Output:

Waiting for input...
Coin inserted, select item...
Item delivered, thank you!
Dispensing item...

Dictionary-based FSM Implementation Alternatively, you can implement an FSM using dictionaries or lookup tables to define state transitions. Here's an example:

transitions = {}

def idle_state(input_value):
    if input_value == "coin":
        print("Coin inserted, select item...")
        return "coin_inserted"
    else:
        print("Waiting for input...")
        return "idle"

def coin_inserted_state(input_value):
    if input_value == "select":
        print("Item delivered, thank you!")
        return "idle"
    else:
        print("Invalid input, please try again.")
        return "coin_inserted"

transitions["idle"] = idle_state
transitions["coin_inserted"] = coin_inserted_state

def run_fsm():
    current_state = "idle"
    while True:
        input_value = input("Enter input: ")
        current_state = transitions[current_state](input_value)

Running the Dictionary-based FSM To run the dictionary-based FSM, simply call the run_fsm() function:

run_fsm()

Input:

Enter input: coin
Enter input: select
Enter input: invalid

Output:

Waiting for input...
Coin inserted, select item...
Item delivered, thank you!
Waiting for input...
Invalid input, please try again.

FSM Design Considerations When designing FSMs, it's essential to consider the following:

  • Identify all possible states and transitions.
  • Define clear rules for state transitions based on inputs or events.
  • Ensure that the FSM is deterministic and free from ambiguities.
  • Consider error handling and invalid inputs or events.

FSM Applications FSMs have a wide range of applications, including:

  • User interface design (e.g., modal dialogs, wizards)
  • Protocol implementation (e.g., network protocols, communication protocols)
  • Control systems (e.g., traffic lights, elevators)
  • Natural language processing (e.g., parsing, text generation)
  • Game development (e.g., character behavior, level design)

Advantages and Limitations of FSMs Advantages of FSMs:

  • Simple and easy to understand
  • Deterministic behavior
  • Well-suited for modeling sequential processes

Limitations of FSMs:

  • Can become complex for systems with many states and transitions
  • Not suitable for modeling concurrent or parallel processes
  • May require additional data structures for more complex scenarios

Resources and Further Reading Here are some resources for further reading on FSMs:

  • "Finite State Machines in Python" (Python documentation)
  • "Finite State Machines" (Wikipedia)
  • "Implementing Finite State Machines in Python" (Real Python)
  • "Finite State Machines: Theory and Implementation" (Michael Sipser)

More in OOP and design patterns

  1. Mastering Inheritance and Polymorphism in Python11 min

    Inheritance and polymorphism are fundamental concepts in object-oriented programming (OOP) that enhance code reusability, flexibility, and maintainability....

  2. Dunder Methods in Python6 min

    Dunder methods, short for "double underscore" methods, are special methods in Python that allow you to define how objects of a class behave in various...

  3. Mastering Python Data Classes10 min

    Data Classes are a powerful feature introduced in Python 3.7 that simplifies the creation of classes primarily used for storing data. They automatically...

  4. Design Patterns in Python6 min
  5. Mastering Python Decorators6 min

    Decorators are special functions that modify the behavior of other functions without directly changing their source code. They follow the wrapper pattern...

  6. Dependency Inversion Principle in Python:4 min

    The Dependency Inversion Principle (DIP) is one of the core principles of the SOLID principles in object-oriented programming. It states that high-level...