Taq Karim
Posted on April 13, 2020
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)
Posted on April 13, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 13, 2024