- Python 101: How to Change a Dict Into a Class
- Python class from dict
- # Creating class instances from a Dictionary in Python
- # Taking keyword arguments when creating an instance
- # Replacing spaces in dictionary keys with underscores
- # Initializing attributes to None
- # Creating class instances from a Dictionary using unpacking
- # Additional Resources
- Python creating class instances from dictionary
- 2 Answers 2
- With the dictionary:
- Generate python class from dictionaries
- 1 Answer 1
Python 101: How to Change a Dict Into a Class
I work with a lot of dictionaries at my job. Sometimes the dictionaries get really complicated with lots of nested data structures embedded within them. Recently I got a little tired of trying to remember all the keys in my dictionaries so I decided to change one of my dictionaries into a class so I could access the keys as instance variables / attributes. If you’ve ever gotten sick
Here’s one simple way to do it:
######################################################################## class Dict2Obj(object): """ Turns a dictionary into a class """ #---------------------------------------------------------------------- def __init__(self, dictionary): """Constructor""" for key in dictionary: setattr(self, key, dictionaryPython class from dict) #---------------------------------------------------------------------- if __name__ == "__main__": ball_dict = ball = Dict2Obj(ball_dict)
This code uses setattr to add each of the keys as attributes to the class. The following shows some examples of how it works:
>>> ball.color ‘blue’ >>> ball.size ‘8 inches’ >>> print ball
When we print the ball object, we get a rather unhelpful string back from the class. Let’s override the __repr__ method of our class and make it print out something a little more useful:
######################################################################## class Dict2Obj(object): """ Turns a dictionary into a class """ #---------------------------------------------------------------------- def __init__(self, dictionary): """Constructor""" for key in dictionary: setattr(self, key, dictionaryPython class from dict) #---------------------------------------------------------------------- def __repr__(self): """""" return "" % self.__dict__ #---------------------------------------------------------------------- if __name__ == "__main__": ball_dict = ball = Dict2Obj(ball_dict)
Now if we print out the ball object, we’ll get the following:
This is a little unintuitive in that it is printing out a dictionary using the class’s internal __dict__ rather than just the attribute names. This is more a matter of taste than anything, but let’s try to get just the method names:
######################################################################## class Dict2Obj(object): """ Turns a dictionary into a class """ #---------------------------------------------------------------------- def __init__(self, dictionary): """Constructor""" for key in dictionary: setattr(self, key, dictionaryPython class from dict) #---------------------------------------------------------------------- def __repr__(self): """""" attrs = str([x for x in self.__dict__]) return "" % attrs #---------------------------------------------------------------------- if __name__ == "__main__": ball_dict = ball = Dict2Obj(ball_dict)
Here we just loop over the contents of __dict__ and return a string with just a list of the keys, which match up with the attribute names. You could have also done it like this:
attrs = str([x for x in dir(self) if "__" not in x])
I’m sure there are lots of other ways to accomplish this sort of thing as well. Regardless, I found this little piece of code helpful in some of my work. Hopefully you’ll find it useful too.
Python class from dict
Last updated: Feb 21, 2023
Reading time · 3 min
# Creating class instances from a Dictionary in Python
To create class instances from a dictionary:
- Take a dictionary from the class’s __init__() method.
- Iterate over the dictionary’s items.
- Use the setattr method to assign each key-value pair as an instance attribute.
Copied!class Developer(): def __init__(self, dictionary): for key, value in dictionary.items(): setattr(self, key, value) my_dict = 'name': 'bobbyhadz', 'salary': 50, 'language': 'Python'> bob = Developer(my_dict) print(bob.name) # 👉️ bobbyhadz print(bob.salary) # 👉️ 50 print(bob.language) # 👉️ Python
The _ _ init _ _ () method takes a dictionary and sets its key-value pairs as instance attributes.
We used a for loop to iterate over the dictionary’s items.
The dict.items method returns a new view of the dictionary’s items ((key, value) pairs).
Copied!my_dict = 'name': 'bobbyhadz', 'salary': 50, 'language': 'Python'> # 👇️ dict_items([('name', 'bobbyhadz'), ('salary', 50), ('language', 'Python')]) print(my_dict.items())
On each iteration, we use the setattr() function to set each key-value pair as an attribute on the instance.
Copied!for key, value in dictionary.items(): setattr(self, key, value)
The setattr() function takes the object, the attribute name and the value as arguments.
# Taking keyword arguments when creating an instance
You can also tweak the __init__() method to take keyword arguments after the dictionary.
Copied!class Developer(): def __init__(self, dictionary, **kwargs): # 👇️ print(dictionary) # 👇️ print(kwargs) for key, value in dictionary.items(): setattr(self, key, value) for key, value in kwargs.items(): setattr(self, key, value) my_dict = 'name': 'bobbyhadz', 'salary': 50, 'language': 'Python'> bob = Developer(my_dict, tasks=['develop', 'test'], age=30) print(bob.name) # 👉️ bobbyhadz print(bob.tasks) # 👉️ ['develop', 'test']
The class’s __init__() method optionally takes keyword arguments after the dictionary.
However, you are not required to pass keyword arguments if you don’t have any.
# Replacing spaces in dictionary keys with underscores
If your dictionary contains keys with spaces, use the str.replace() method to replace each space with an underscore.
Copied!class Developer(): def __init__(self, dictionary): for key, value in dictionary.items(): setattr(self, str(key).replace(' ', '_'), value) my_dict = 'first name': 'bobbyhadz', 'salary': 50, 'language': 'Python'> bob = Developer(my_dict) print(bob.first_name) # 👉️ bobbyhadz print(bob.salary) # 👉️ 50 print(bob.language) # 👉️ Python
The first name key contains a space, so we used the str.replace() method to replace any spaces in the dictionary’s keys with underscores.
# Initializing attributes to None
If you get linting errors when you try to access attributes on each instance, e.g. «Instance of ‘Developer’ type has no ‘X’ member», initialize the attributes to None .
Copied!class Developer(): def __init__(self, dictionary): self.name = None self.salary = None self.language = None for key, value in dictionary.items(): setattr(self, str(key).replace(' ', '_'), value) my_dict = 'first name': 'bobbyhadz', 'salary': 50, 'language': 'Python'> bob = Developer(my_dict) print(bob.name) # 👉️ bobbyhadz print(bob.salary) # 👉️ 50 print(bob.language) # 👉️ Python
We initialized all attributes to None , so we can access the attributes on each instance without getting linting errors.
# Creating class instances from a Dictionary using unpacking
An alternative approach to consider is to define the properties in the __init__() method and unpack the dictionary’s key-value pairs when instantiating the class.
Copied!class Developer(): def __init__(self, name, salary, language): self.name = name self.salary = salary self.language = language my_dict = 'name': 'bobbyhadz', 'salary': 50, 'language': 'Python'> bob = Developer(**my_dict) print(bob.name) # 👉️ bobbyhadz print(bob.salary) # 👉️ 50 print(bob.language) # 👉️ Python
We used the ** operator to unpack the key-value pairs of the dictionary when instantiating the class.
You can imagine that the dictionary’s key-value pairs got passed as keyword arguments to the class.
# Additional Resources
You can learn more about the related topics by checking out the following tutorials:
I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
Python creating class instances from dictionary
I have class with a lot of fields that can be changed while my program is running, but when I create new object in my init I only can change some of them, I want to save those changes to JSON file and later be able to create new object with those variables. Is there any other way to do it other than making my init taking like 100 arguments? In other words I would love it to be sth like that:
class MyClass: def __init__(self, q, w): self.q = q self.w = w self.e = 30 self.r = 40 a = MyClass(10,20) dct = print('before:', tmp.q, tmp.w, tmp.e, tmp.r) for i in dct: #do sth here print('after:', tmp.q, tmp.w, tmp.e, tmp.r)
before: 10 20 30 40 after: 100 200 300 400
2 Answers 2
Here is how you can do that with keyword arguments:
class MyClass: def __init__(self, **q): self.__dict__.update(q) a = MyClass(a=10, b=20, c=50, d=69) print(a.a) print(a.b) print(a.c) print(a.d)
With the dictionary:
class MyClass: def __init__(self, **q): self.__dict__.update(q) dct = a = MyClass(**dct) print(a.q, a.w, a.e, a.r)
I see, so if I want to create «fresh» instance I’d have to create it with dct that has all «starting» values, and if I create one that was already changed I use another one. that works, thank you 🙂
Arguable which is better and is contextual and subjective, but omitting ** in front of **q to avoid having to unpack a dict (and also allowing [[k,v],[k,v]. ] form input) may make more sense, not only to avoid unpacking/packing, but also because logically MyClass is basically a wrapper class around the dict (or a level higher the JSON data), and it is only natural that the constructor take input in a form closer to an actual dict (and thus also the JSON) rather than just arbitrary named parameters, unnecessarily using the packing of arbitrary parameters and requirnig unpacking of input data.
(Important to note that this will not use getters setters if they are defined). And an alternative syntax available here using vars(): stackoverflow.com/questions/9204671/… I still don’t really see any major problem with this implementation, but these things should all be noted.
Instead of manipulating the class instances __dict__ , I’d recommend using the setattr method.
class MyClass: def __init__(self, new_vals): for k, v in new_vals.items(): setattr(self, k, v) dct = a = MyClass(dct) print(a.q, a.w, a.e, a.r)
Imho there is a reason why internals such as __dict__ have two leading underscores. My general recommendation would be to avoid accessing any attributes/mehods with two leading underscores as long as possible. Also see below for a reference to the Python documentation considering this topic.
And if you want to reduce it to a one-liner, you could also use a «dummy» list comprehension. The underscore catches the None return, but it is not necessarily required.
class MyClass: def __init__(self, new_vals): _ = [setattr(self, k, v) for k, v in new_vals.items()]
A short reference to the Python documentation on manipulating the built in __dict__ attribute:
A special attribute of every module is __dict__ . This is the dictionary containing the module’s symbol table. Modifying this dictionary will actually change the module’s symbol table, but direct assignment to the __dict__ attribute is not possible (you can write m.__dict__[‘a’] = 1 , which defines m.a to be 1 , but you can’t write m.__dict__ = <> ). Modifying __dict__ directly is not recommended.
Generate python class from dictionaries
Everything works well until I added the lines to also translate the dict values from the dictionaries to their own classes. My code just stopped without any errors what so ever. Here is an example of js_obj
>, 'date': 1577954356, 'edit_date': 0, 'id': 1827667968, 'is_channel_post': False, 'is_outgoing': False, 'media_album_id': '0', 'reply_to_message_id': 0, 'sender_user_id': 416195206, 'ttl': 0, 'ttl_expires_in': 0.0, 'via_bot_user_id': 0, 'views': 0>```
You should probably make a copy of the BaseClass and not use TdObject as its default value because classes are mutable.
1 Answer 1
I think you may be confusing classes and objects here. The values of attributes would typically be instances of classes, i.e. objects, not classes themselves. That’s why things break if you set the value of the attributes you’re creating to classes.
If you’re actually just looking to create an object from a dictionary (and not a class which you can then use to instantiate multiple objects), something like this works:
class FromDict: def __init__(self, dct): for key in dct: setattr(self, key, dctPython class from dict if not isinstance(dctPython class from dict, dict) else FromDict(dctPython class from dict))
If you do need a class factory, you’ll need more code to properly instantiate the objects that need to be assigned as attribute values. You could generate setters for each of those and generate more inner classes in your new class, but I doubt that will be very useful and is a bit more to cover than a simple answer here warrants.