JSON for Custom Python Objects
In this video you’ll learn how to work with types that are non-serializable.
The json
module is not capable of serializing all Python types. Non-serializable types include custom types created from classes, as well as the built-in complex
type used to represent imaginary numbers.
json_str = json.dumps(6 + 2j) # cannot serialize complex object
In order to serialize these types, we must extract the necessary data to recreate the object.
The complex
type stores both the real and imaginary parts of the complex number as float
. Floats are a type that can be serialized by the dump()
and dumps()
methods. In the next video, you’ll learn how to encode them into JSON format.
00:00 Welcome back to our series on working with JSON data in Python. In this video, we’re going to learn how to encode custom Python objects or otherwise non-serializable types into JSON format.
00:14
I’m here in Visual Studio Code, and I’ve already typed out a bit of code here to save some time. I’ve got a generic Person
class and now I want to serialize a Person
object into a string.
00:27
I’ll move down to the bottom here and I’ll type json_str = json.dumps(Person())
and I’ll give him a name
of "Will"
and an age
of 29
.
00:41
What I’m trying to do here is create a new Person
object and immediately serialize that into a string. Now I’ll simply print the JSON-formatted string to the console.
00:52
So if I right-click here and I choose Run Code, we’ll see that we get a TypeError
. Python is telling us that our Person
object is not serializable. Let’s take a look at why this is happening.
01:05
Unfortunately for us, the built-in dumps()
module only knows how to serialize built-in types. That’s why we can say something like json.dumps()
and pass in 3.14
and it will have no problem. But some types are not so easily serializable, like the Python complex
type or any other custom type that we create.
01:28
The complex
type is used to store complex numbers, which are numbers with an imaginary component. This arises when we try to take the square root of a negative number—but honestly, that just brings back bad memories from high school math class, so let’s not talk too much about it. What’s important here is that you know the complex
type is non-serializable, just as our custom Person
type is.
01:53 But we still want to store these objects in our JSON files, so what gives? That’s where simplification comes in, and I already like the name. What we need to do is break the object down into simpler parts that can individually be serialized. We should ask ourselves: what is the minimum amount of information necessary to recreate this object?
02:17
Remember, whoever deserializes our JSON on the other end might not know anything about our Person
object, so we need to make sure that we serialize everything that’s needed. From here on out, I’m going to use the complex
type as an example of how to serialize an otherwise non-serializable type. First, we have to understand how the complex
type works. It’s got two parts: a real part and an imaginary part. In the diagram on the right here, 6 + 2j
means that 6.0
is our real part, and 2.0
is our imaginary part. Fortunately, each of those numbers can be serialized, and as far as we’re concerned right now, that’s all we need to recreate our complex
object after the JSON has been deserialized.
03:07
Remember, the deserialization operation will likely output either a dictionary or a list, so whoever deserializes it is most likely only going to get a list with the numbers 6
and 2
in it, and nothing else.
03:22
Once we have the data from our original object, we can recreate that object by passing the data into the necessary constructor. So in this example here, pretend that we’ve serialized the complex number 3 + 8j
. Of course, we can’t actually serialize the complex
object in that form, so we just serialized 3
and 8
. The person on the other end just deserialized our JSON, and now they’ve got a list of [3, 8]
to work with. In order to recreate the original object, all they need to do is pass those numbers into the constructor for the complex
class. And as you can see on screen, that gives them a complex
object with the same value as our original complex
object. There’s one more little hiccup we’ll see later on, but for now, let’s see how we can handle encoding the complex
type within our code.
Abby Jones on June 28, 2019
I think it is more involved than that, but I am not sure how. I am still learning as well.
Arjun Umathanu on Oct. 7, 2020
import json
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
self.alive = True
def serialize(self):
return {'name': self.name, 'age': self.age, 'alive': self.alive}
>>> json_str = json.dumps(Person('Will', 29).serialize())
>>> print(json_str)
{"name": "Will", "age": 29, "alive": true} # output :D
Become a Member to join the conversation.
terrymiddleton on May 11, 2019
So…after a little Google searching on serialize and deserialize of json, it has become apparent that the process of serializing and deserializing is simply taking a json object and converting it to a string that can be worked with.
Is this correct.
With an object, it has a certain structure and framework that does not work well/properly with evaluating or working with strings. An output to a file has to be put in a string format so it can be written, while the data may reside in an object.
For example, if I wanted to write out all the books in a certain library and all the books were sitting in an object called library, I would need to “convert” all the books within the object to a string so I could write it to a file or work with it in code.
Am I thinking correctly on this? Terry