Skip to content

🧊 Immutable Configuration in Python Using a Custom Class - ES-308 #12

@EED85

Description

@EED85

📌 Problem

In many applications, configuration data (e.g., database credentials, API keys, feature flags) is loaded at startup and should remain unchanged throughout the program's lifecycle. However, Python dictionaries are mutable by default, which can lead to accidental or unauthorized modifications.

✅ Goal

Create a fully immutable configuration object, including nested dictionaries, lists, and sets, to ensure the integrity of application settings after initialization.


🛠️ Solution: Custom ImmutableConfig Class

We define a class that:

  • Recursively freezes nested structures (dict, list, set)
  • Exposes read-only access via __getitem__
  • Optionally provides a method to export the config as a regular dict
from types import MappingProxyType

class ImmutableConfig:
    def __init__(self, data):
        self._data = self._deep_freeze(data)

    def _deep_freeze(self, obj):
        if isinstance(obj, dict):
            return MappingProxyType({k: self._deep_freeze(v) for k, v in obj.items()})
        elif isinstance(obj, list):
            return tuple(self._deep_freeze(i) for i in obj)
        elif isinstance(obj, set):
            return frozenset(self._deep_freeze(i) for i in obj)
        else:
            return obj

    def __getitem__(self, key):
        return self._data[key]

    def __repr__(self):
        return f"ImmutableConfig({dict(self._data)})"

    def to_dict(self):
        # Optional: return a deep copy as a regular dict
        import copy
        return copy.deepcopy(self._data)

🧪 Example Usage

config_data = {
    'db': {'host': 'localhost', 'port': 5432},
    'api': {'key': 'abc123', 'timeout': 30},
    'features': ['auth', 'logging']
}

config = ImmutableConfig(config_data)

print(config['db']['host'])  # Output: 'localhost'

# Attempting to mutate will raise an error
config['db']['host'] = '127.0.0.1'  # ❌ TypeError

📎 Notes

  • Requires Python 3.3+ (MappingProxyType is part of the standard types module).
  • You can extend the class to support:
    • JSON serialization
    • Schema validation
    • Logging access or audit trails

Let me know if you'd like a version with JSON export or schema validation built in!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions