Home > Mobile >  Using namespace with nested dictionaries with two levels and two keys at second level
Using namespace with nested dictionaries with two levels and two keys at second level

Time:01-07

I have the following info structure:

items= {i1: {ref: i1_ref, attrs: {attr1: 'red', attr2: 'low'}}, i2: {ref: i2_def, attrs: {attr1: 'green', attr2: 'hight'}}}

i1, i2... are strings.

i1_ref, i2_ref... are strings also.

I would like have an object i to be able to retrieve the information as follows:

  • i.i1 to get the ref from i1 (i1_ref value), i.i2 to get the ref from i2 (i2_ref value).
  • i.i1.attrs to get the nested dictionary of attributes from i1,
  • i.i2.attrs to get the nested dictionary of attributes from i2.

Code:

print(i.i1)
>>> i1_ref
print(i.i1.attrs)
>>> {attr1: 'red', attr2: 'low'}

CodePudding user response:

A solution that adds attributes to a subclass of str to get the desired behavior.

items = {
    "i1": {"ref": "i1_ref", "attrs": {"attr1": 'red', "attr2": 'low'}},
    "i2": {"ref": "i2_def", "attrs": {"attr1": 'green', "attr2": 'hight'}}
}

# Subclass string, so we can add attributes to the instance.
class Item(str):
    def __new__(cls, d):
        s = super().__new__(cls, d["ref"])
        s.attrs = d["attrs"]
        return s

# Just a class that holds the dict keys as attributes
# and Item objects as their values.
class Items:
    def __init__(self, d):
        for it in d:
            setattr(self, it, Item(d[it]))

i = Items(items)
print(i.i1)
print(i.i1.attrs)

output:

i1_ref
{'attr1': 'red', 'attr2': 'low'}

Different solution with SimpleNamespace:

from types import SimpleNamespace

items = {
    "i1": {"ref": "i1_ref", "attrs": {"attr1": 'red', "attr2": 'low'}},
    "i2": {"ref": "i2_def", "attrs": {"attr1": 'green', "attr2": 'hight'}}
}

class Item(SimpleNamespace):
    def __str__(self):
        return self.ref

i = SimpleNamespace(**{k:Item(**v) for k,v in items.items()})

print(i.i1)
print(i.i1.attrs)

Although the printed output is exactly the same, the behavior is a bit different:
While i.i1 from the first solution really is a string (with attached attrs), i.i1 from the second solution is a SimpleNamespace object whose string representation is the ref.
This means i.i1 == "i1_ref" is True for the first solution, but for the second solution you need to write str(i.i1) == "i1_ref" or i.i1.ref == "i1_ref".

  •  Tags:  
  • Related