
Python Programming Tips
In one of my previous articles, I have introduced probably the best practice of Object-Oriented Programming (OOP) in Python, which is using the library "Attrs".
However, in most cases, we use OOP is probably due to it can be serialised into strings such as JSON strings. More conveniently, we should also be able to deserialise it back to class instances for other purposes.
For example, one of the most popular usages of these is Data Access Objects (DAO). So, we may implement CRUD functions with the objects to seamlessly integrate with the persistence layer.
Therefore, most of the time, we might want to serialise the Python objects into JSON for transferring purposes. Reversely, we also want to deserialise JSON strings into Python objects if we’re using Python to receive the data as JSON types.
In this article, I’ll introduce another library – "Cattr" which can be used together with "Attr". I’ll focus on "Cattr", so if you are interesting what are the capabilities that "Attr" has, please check out the article above mentioned.
Installation and Importing

First of all, we need to install these two libraries using pip
.
pip install attrs
pip install cattrs
In this article, all we need from attr
are the annotations for the class and the attribute function, so let’s import them together with the library cattr
.
from attr import attrs, attrib
import cattr
Basic Usage of Cattr

Basically, cattr
is used for converting the data objects between structured and unstructured states. For example, instances from classes are considered structured data, whereas Python dictionaries and JSON objects are considered unstructured data.
Suppose we want to regulate data in a list with uncertain, we can use cattr
as follows.
from typing import Tuple
cattr.structure([1.01, True, False, "2", "I will be ignored"], Tuple[int, int, int, int])

Please note that we are using the type alias "Tuple" from the typing
library, which is built-in to Python 3. If you are not sure what it is, here is the official documentation.
typing – Support for type hints – Python 3.8.3 documentation
In this example, the float, boolean and string objects are regulated into integers as specified in the template. Also, the 5th object in the list has been ignored because there are only 4 elements in the template.
Cattr Works with Attr

cattr
works best with attr
when dealing with classes.
Suppose we define the class as follows.
@attrs
class Person:
name = attrib()
age = attrib()
def tell_age(self):
print(f'My name is {self.name} and my age is {self.age}.')
Of course, as introduced in my previous article, attr
can be used for serialising the instances into dictionaries.
from attr import asdict
p1 = Person('Chris', 32)
asdict(p1)

Of course, cattr
can do this as well.
cattr.unstructure(p1)

It looks like the asdict()
function from attr
is more intuitive. However, this is just serialisation. What if we got a dictionary and want to deserialise it into a Person
object? This time attr
cannot help, but we can use cattr
.
p2 = cattr.structure({'name': 'Chelsea', 'age': 1}, Person)

Cattr Works with a List of Dictionaries

The above example is only deserialising a single dictionary. In practice, that’s not ideal. What if we want to deserialise a list of dictionaries into Python objects? In the example below, we have three dictionaries to be deserialised in a list.
p_list_raw = [
{'name': 'Alice', 'age': 20},
{'name': 'Bob', 'age': 25},
{'name': 'Chris', 'age': 32}
]
To implement this, we will need to define a "template", too. Please note that the argument we passed in is not a "Person" anymore, but a list of "Person" objects. Therefore, we will need to use the typing alias again.
from typing import List
p_list = cattr.structure(p_list_raw, List[Person])

Therefore, we got a list of person objects from the list of person dictionaries.
Cattr Works with JSON

Of course, we are not satisfied by only serialise/deserialise to Python dictionaries. We want it to be a JSON object! It is also very easy. In fact, the only thing we need to do is to import the json
library which is also a Python built-in module.
Recall that we have a list of Python objects p_list
from the previous example.

To serialise it into a JSON array, simply use cattr
together with json.dumps()
function as follows.
import json
json_obj = json.dumps(cattr.unstructure(p_list))
print(json_obj)

To deserialise the JSON array into a list of Python objects is also very easy. Simple use the json.loads()
function in conjunction with cattr
.
p_list = cattr.structure(json.loads(json_obj), List[Person])

Just don’t forget we need the typing alias "List" as the template.
The above example also showed that the deserialised objects can be called with their class functions, of course 🙂
Summary

In this article, I have introduced how to use cattr
together with attr
libraries to achieve Python objects serialising into dictionaries/JSON, as well as dictionaries and JSON objects deserialising into Python objects in an extremely easy way.
Given that this is usually not an easy job in most of the other programming languages, at least not that fast to be implemented, I would say that it reflects why people love Python in a single aspect.
All the code in this article can be found here:
If you feel my articles are helpful, please consider joining Medium Membership to support me and thousands of other writers! (Click the link above)