Skip to content

Instantly share code, notes, and snippets.

@SamWolski
Created November 26, 2024 12:45
Show Gist options
  • Save SamWolski/ef3b0258ba504a558a87096a370501a0 to your computer and use it in GitHub Desktop.
Save SamWolski/ef3b0258ba504a558a87096a370501a0 to your computer and use it in GitHub Desktop.
Python dict with fallback
from collections import UserDict
from collections.abc import Mapping
from typing import Optional
###############################################################################
class FallbackDict(UserDict):
"""A dict-like which falls back on another mapping for missing keys
"""
def __init__(self, fallback: Optional[Mapping] = None, **kwargs):
self._fallback = fallback if fallback is not None else {}
super().__init__(**kwargs)
def __getitem__(self, key):
return self.data.get(key, self._fallback[key])
def __repr__(self) -> str:
rstr = repr(self.data)
if self._fallback:
rstr += f" with fallback {repr(self._fallback)}"
return rstr
class NestedFallbackDict(UserDict):
"""A dict-like which falls back on another mapping for missing keys, with
recursive behaviour for nested mappings
If the value to be fetched is a Mapping subclass, a new NestedFallbackDict
is constructed out of the fetched Mappings in both the target and fallback
dicts.
This can be thought of as a deepmerged version of the FallbackDict.
"""
def __init__(self, fallback: Optional[Mapping] = None, **kwargs):
self._fallback = fallback if fallback is not None else {}
super().__init__(**kwargs)
def __getitem__(self, key):
if key in self.data:
value = self.data[key]
if isinstance(value, Mapping):
value_fallback = self._fallback.get(key, {})
value_nfd = NestedFallbackDict(value_fallback)
value_nfd.update(value)
return value_nfd
return value
else:
return self._fallback[key]
def __repr__(self) -> str:
rstr = repr(self.data)
if self._fallback:
rstr += f" with fallback {repr(self._fallback)}"
return rstr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment