Memento Pattern in Python: Save and Restore Object State
Implement the Memento design pattern to snapshot and restore an object's state, demonstrated with a text editor undo feature.
Python code
56 linesclass TextEditor:
def __init__(self, text="", cursor_pos=0):
self.text = text
self.cursor_pos = cursor_pos
def type_text(self, new_text):
self.text += new_text
self.cursor_pos += len(new_text)
def move_cursor(self, pos):
self.cursor_pos = max(0, min(pos, len(self.text)))
def create_memento(self):
return EditorMemento(self.text, self.cursor_pos)
def restore_from_memento(self, memento):
self.text = memento.text
self.cursor_pos = memento.cursor_pos
def __str__(self):
return f"Text: '{self.text}' | Cursor: {self.cursor_pos}"
class EditorMemento:
def __init__(self, text, cursor_pos):
self.text = text
self.cursor_pos = cursor_pos
class History:
def __init__(self, editor):
self.editor = editor
self.states = []
def backup(self):
self.states.append(self.editor.create_memento())
def undo(self):
if self.states:
memento = self.states.pop()
self.editor.restore_from_memento(memento)
else:
print("No states to undo")
if __name__ == "__main__":
editor = TextEditor()
history = History(editor)
editor.type_text("Hello")
history.backup()
editor.type_text(" World")
print(editor)
history.undo()
print(f"After undo: {editor}")
Output
Text: 'Hello World' | Cursor: 11
After undo: Text: 'Hello' | Cursor: 5
How it works
The Memento pattern captures an object's internal state in a separate memento object without exposing its implementation details. Here, TextEditor.create_memento returns an EditorMemento containing the current text and cursor position. The History class stores these mementos and provides an undo operation that restores the editor to a previous state. This keeps the editor class decoupled from the undo management logic. The pattern is particularly useful for implementing undo/redo features while preserving encapsulation.
Common mistakes
- Storing direct references to mutable objects in mementos, which can be modified externally; use immutable or copied data.
- Not limiting the history size, causing memory leaks or unbounded growth.
- Restoring state without validating the memento, leading to unexpected errors if the memento is corrupted.
Variations
- Use the `copy.deepcopy` method to create snapshots of complex object graphs instead of a custom memento class.
- Use Python's built-in `undo` patterns with command objects that each store the inverse operation.
Real-world use cases
- Implementing an undo/redo feature in desktop or web text editors, such as Ctrl+Z and Ctrl+Y.
- Providing rollback functionality in database-like structures, like returning to a previous schema or configuration state.
- Supporting transaction-like behavior in stateful services, such as reverting a user's form inputs to a saved draft.
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.