How to convert a Python dict to a Class object
Asked Answered
V

4

11

I am looking for a simple way to directly convert a python dict to a custom object as follows, while not breaking intellisense. The result should not be read-only, it should behave just like a new object.

d = {
    "key1": 1,
    "key2": 2
}

class MyObject(object):
    key1 = None
    key2 = None

# convert to object o

# after conversion
# should be able to access the defined props
# should be highlighted by intellisense
print(o.key1)
# conversion back to dict is plain simple
print(o.__dict__)
Variegated answered 9/12, 2019 at 14:6 Comment(1)
for key, value in d.items(): setattr(o, key, value)Angelangela
C
19

Your object has no fields, just class attributes. You need to create a __init__ method, some will call it a constructor but it is not actually a constructor as understood by other languages so lets avoid calling it like that.

class MyObject:
    def __init__(self, d=None):
        if d is not None:
            for key, value in d.items():
                setattr(self, key, value)

d = {
    "key1": 1,
    "key2": 2,
}

o = MyObject(d)

Note: the above code will try to set all key-value pairs in the dict to fields in the object. Some valid keys such as "key.1" will not be valid field names (it will actually be set but you will not be able to get it with o.key.1).

Cureton answered 9/12, 2019 at 14:13 Comment(4)
Just that it requires the creation of a new object like this o = MyObject({}) which is no big problem but can it be avoided?Variegated
Sure, does my updated answer fulfill your requirements? o = MyObject() should work fine now.Cureton
@AlexPredescu you will probably want to do some key checks inside the loop before the setattr call to find characters that you do not want (such as .). In case performance and memory usage is an important factor, knowing the keys that the dicts will have would allow as to use __slots__.Cureton
For Python 3.7+, see other answer using dataclassesCaprification
D
9

I'd use a dataclass (requires Python 3.7+):

from dataclasses import dataclass


@dataclass
class MyObject:
    key1: int = None
    key2: int = None


d = {
    "key1": 1,
    "key2": 2,
}

o = MyObject(**d)

print(o)  # MyObject(key1=1, key2=2)
print(vars(o))  # {'key1': 1, 'key2': 2}

dataclass will automatically generate __repr__, __eq__, __hash__, and some other methods for you.

Dermatitis answered 18/10, 2023 at 16:17 Comment(1)
It even manages nested classes i.e. class MyClass:\prop1: MyClass2. Beautiful stuff!Caprification
M
3
dict_ = {"User" :{"Name" : "SQWiperYT", "ID" : 10, "Other" : {"ID" : 1}}}
import json


class OurObject:
    def __init__(self, /, **kwargs):
        self.__dict__.update(kwargs)

    def __repr__(self):
        keys = sorted(self.__dict__)
        items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
        return "{}({})".format(type(self).__name__, ", ".join(items))

    def __eq__(self, other):
        return self.__dict__ == other.__dict__
      
      
x = json.dumps(dict_)
y = json.loads(x, object_hook=lambda d: OurObject(**d))

# See How it Works
y.User
>>> OurObject(ID=10, Name='SQWiperYT', Other=OurObject(ID=1))
y.User.ID
>>> 10
y.User.Name
>>> 'SQWiperYT'
y.User.Other.ID
>>> 1

This is the thing you need actually.

Mcmahan answered 11/7, 2020 at 7:30 Comment(2)
Please consider explaining your solution and why does it solve the problem.Instantaneous
note for the future: you overcomplicate it too muchCastellatus
E
0

a slightly modified example based on the article https://www.blog.pythonlibrary.org/2014/02/14/python-101-how-to-change-a-dict-into-a-class/

class Dict2Obj(object):
    def __init__(self, dictionary):
        for key in dictionary:
            setattr(self, key, dictionary[key])
    
    def __repr__(self):
        return "<dict2obj: %s>" % self.__dict__

ball_dict = {"color":"blue", "size":8, "material":"rubber", "other": {"speed": 15, "mass": 1.2 }}
ball = Dict2Obj(ball_dict)
print (ball)

the nested dicctionary is not converted into a class itself. It is a similar result as the solution using dataclass but without having __eq__ and __hash__

Extremity answered 17/12, 2023 at 14:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.