Borg pattern shared state in Python
Implement the Borg pattern to share state across class instances by assigning a class-level dictionary to each instance's __dict__.
Python code
30 linesclass Borg:
_shared_state = {}
def __init__(self):
self.__dict__ = Borg._shared_state
class ConfigManager(Borg):
def __init__(self):
super().__init__()
if not hasattr(self, "settings"):
self.settings = {}
def set(self, key, value):
self.settings[key] = value
def get(self, key):
return self.settings.get(key)
if __name__ == "__main__":
config1 = ConfigManager()
config2 = ConfigManager()
config1.set("theme", "dark")
print(config1.get("theme"))
print(config2.get("theme"))
print(config1 is config2)
print(config1.__dict__ is config2.__dict__)
Output
dark
dark
False
True
How it works
The Borg pattern (also called Monostate) ensures all instances share the same internal state by pointing each instance's __dict__ to the same class-level dictionary _shared_state. Because __dict__ holds instance attributes, assigning it once in __init__ makes every instance read and write to the same storage. The super().__init__() call in ConfigManager ensures the shared dictionary is set before accessing settings, and the hasattr guard prevents resetting existing shared data. Unlike the Singleton pattern, instances remain distinct objects (is returns False), but their attribute dictionaries are identical, so state is synchronized automatically.
Common mistakes
- Forgetting to call `super().__init__()` in subclasses, leaving instance dicts unset
- Reassigning `self.settings = {}` unconditionally, wiping shared state on each new instance
- Assuming `config1 is config2` will be True—Borg keeps separate objects
- Mutating `_shared_state` directly instead of through instance methods
Variations
- Use `__new__` to return a shared instance for a true Singleton pattern
- Set `_shared_state` as a class attribute updated via `__getattr__` for lightweight access
Real-world use cases
- Sharing application configuration across modules without passing objects explicitly.
- Maintaining a global connection pool or cache that all service instances reference.
- Tracking user session data across multiple handler objects in a web application.
Sponsored
More from OOP & classes
- Add property getter setter validation in Python easy
- Binary Tree Inorder Traversal in Python easy
- 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
- Compute Derived Fields with @dataclass __post_init__ in Python easy
Keep learning
Related tutorials and quizzes for this topic.