I'm a huge fan of Python3's types.SimpleNamespace
. Basically, it allows us to take a dict, like so:
my_dict = {
"a": 1,
"b": 2,
"c": 3,
}
my_dict["a"] # 1
my_dict["b"] # 2, etc
and manage it like this:
from types import SimpleNamespace
my_namespace = SimpleNamespace(a=1, b=2, c=3)
my_namespace.a # 1
my_namespace.b # 2
my_namespace.c # 3
Alternatively, we could also do something like:
from types import SimpleNamespace
my_dict = {
"a": 1,
"b": 2,
"c": 3,
}
my_namespace = SimpleNamespace(**my_dict)
my_namespace.a # 1
my_namespace.b # 2
my_namespace.c # 3
But - what happens if our my_dict
is nested? Like so:
my_dict = {
"a": {
"d": 4,
},
"b": 2,
"c": 3,
"e": [5,6,7,{
"f": 8,
}]
}
my_namespace = SimpleNamespace(**my_dict)
my_namespace.a # {"d": 4} /womp womp ðŸ˜
my_namespace.a.d # raises Exception! ðŸ˜ðŸ˜
In short, SimpleNamespace
simply does not support this use case. But that's ok! We can extend SimpleNamespace
and build this functionality for ourselves.
Defining RecursiveNamespace
from types import SimpleNamespace
# this is how SimpleNamespace looks when output
SimpleNamespace(**my_dict)
# namespace(a={'d': 4}, b=2, c=3, e=[5, 6, 7, {'f': 8}])
class RecursiveNamespace(SimpleNamespace):
@staticmethod
def map_entry(entry):
if isinstance(entry, dict):
return RecursiveNamespace(**entry)
return entry
def __init__(self, **kwargs):
super().__init__(**kwargs)
for key, val in kwargs.items():
if type(val) == dict:
setattr(self, key, RecursiveNamespace(**val))
elif type(val) == list:
setattr(self, key, list(map(self.map_entry, val)))
# this is how RecursiveNamespace looks when output
RecursiveNamespace(**my_dict)
# RecursiveNamespace(
# a=RecursiveNamespace(d=4),
# b=2,
# c=3,
# e=[5, 6, 7, RecursiveNamespace(f=8)])
So, what's happening here? We establish a new class, RecursiveNamespace
that extends SimpleNamespace
. In the __init__
constructor method, we call SimpleNamespace
's constructor. Then, we just walk through our dictionary and for value that is also a dictionary or list, we instantiate that with RecursiveNamespace
. Ta da.
P.S.
Technically, we don't even really need types.SimpleNamespace
here - we can implement this class without by just adding two lines of code:
class RecursiveNamespace2: # without extending SimpleNamespace!
@staticmethod
def map_entry(entry):
if isinstance(entry, dict):
return RecursiveNamespace(**entry)
return entry
def __init__(self, **kwargs):
for key, val in kwargs.items():
if type(val) == dict:
setattr(self, key, RecursiveNamespace(**val))
elif type(val) == list:
setattr(self, key, list(map(self.map_entry, val)))
else: # this is the only addition
setattr(self, key, val)
Top comments (1)
Thank you for your post!
If your dictionary is serializable, you might as well use the json module to accomplish the same 'nested' effect: