How to Implement the State Pattern in Python
Implement the State design pattern in Python by delegating behavior to state objects, letting a media player change actions dynamically without if-else chains.
Python code
59 linesclass State:
def play(self, player): pass
def pause(self, player): pass
def stop(self, player): pass
class PlayingState(State):
def play(self, player):
return "Already playing"
def pause(self, player):
player.state = PausedState()
return "Pausing playback"
def stop(self, player):
player.state = StoppedState()
return "Stopping playback"
class PausedState(State):
def play(self, player):
player.state = PlayingState()
return "Resuming playback"
def pause(self, player):
return "Already paused"
def stop(self, player):
player.state = StoppedState()
return "Stopping playback"
class StoppedState(State):
def play(self, player):
player.state = PlayingState()
return "Starting playback"
def pause(self, player):
return "Cannot pause - no playback"
def stop(self, player):
return "Already stopped"
class MediaPlayer:
def __init__(self):
self.state = StoppedState()
def play(self):
return self.state.play(self)
def pause(self):
return self.state.pause(self)
def stop(self):
return self.state.stop(self)
def current_state(self):
return type(self.state).__name__
if __name__ == "__main__":
player = MediaPlayer()
print(f"Initial state: {player.current_state()}")
print(player.play())
print(f"State: {player.current_state()}")
print(player.pause())
print(f"State: {player.current_state()}")
print(player.stop())
print(f"Final state: {player.current_state()}")
Output
Initial state: StoppedState
Starting playback
State: PlayingState
Pausing playback
State: PausedState
Stopping playback
Final state: StoppedState
How it works
The State pattern encapsulates each possible state in its own class, so the MediaPlayer simply delegates actions to its current state object. Every state class implements the same interface (play, pause, stop) and transitions to the next state by replacing player.state. This eliminates long conditionals and makes adding new states straightforward — just create another class. The current_state method inspects the actual class name for debugging or display.
Common mistakes
- Having one class with many if-elif branches instead of separate state classes
- Forgetting to pass `self` to the state method calls inside MediaPlayer
- Omitting the fallback `pass` methods in the base State class, causing AttributeError for unsupported actions
Variations
- Use an enum to store state names and a single switch-like method in the player, though it's less extensible.
- Turn state classes into singletons to avoid creating new instances on every transition.
Real-world use cases
- Modeling workflow statuses in a document processing pipeline where actions depend on the current stage.
- Building an order management system where each order status defines allowed operations like cancel or ship.
- Creating a TCP connection handler where network state dictates how to react to incoming packets.
Sponsored
More from OOP & classes
- Add property getter setter validation in Python easy
- Binary Tree Inorder Traversal in Python easy
- Borg pattern shared state in Python medium
- Bridge Pattern in Python: Separate Abstraction from Implementation medium
- Composable Predicates with the &, |, ~ Operators in Python medium
- Composition over Inheritance: How to Build a Wallet Account in Python easy
Keep learning
Related tutorials and quizzes for this topic.