PabloG
PabloG

Reputation: 454

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

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:

Code:

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

Upvotes: 1

Views: 512

Answers (1)

Wups
Wups

Reputation: 2569

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".

Upvotes: 1

Related Questions