Backend Development 7 min read

Custom JSON Encoder and Advanced Serialization Techniques in Python

This article demonstrates how to create custom JSON encoders, serialize and deserialize custom classes, handle circular references, and use various json.dumps parameters such as default, object_pairs_hook, allow_nan, indent, separators, and ensure_ascii to control JSON output in Python.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Custom JSON Encoder and Advanced Serialization Techniques in Python

1. Custom JSON Encoder: When standard json module cannot serialize objects like custom classes or datetime, you can create a subclass of json.JSONEncoder that overrides the default method.

import json
from datetime import datetime

class CustomEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super().default(obj)

data = {
    "name": "Alice",
    "created_at": datetime.now()
}
json_data = json.dumps(data, cls=CustomEncoder)
print("自定义编码器输出:", json_data)

Output: 自定义编码器输出: {"name": "Alice", "created_at": "2024-08-09T12:34:56.789012"}

2. Serialize Custom Class: Define a custom class and a corresponding encoder that returns a serializable dictionary.

import json

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class PersonEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Person):
            return {'name': obj.name, 'age': obj.age}
        return super().default(obj)

p = Person("Bob", 25)
json_data = json.dumps(p, cls=PersonEncoder)
print("序列化自定义类:", json_data)

Output: 序列化自定义类: {"name": "Bob", "age": 25}

3. Deserialize Custom Class: Use an object_hook to convert JSON back into a custom class instance.

import json

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

def person_decoder(obj):
    if '__type__' in obj and obj['__type__'] == 'person':
        return Person(obj['name'], obj['age'])
    return obj

json_data = '{"__type__": "person", "name": "Charlie", "age": 30}'
p = json.loads(json_data, object_hook=person_decoder)
print("反序列化自定义类:", p.name, p.age)

Output: 反序列化自定义类: Charlie 30

4. Handling Circular References: Disable circular reference checks to avoid infinite recursion when objects reference each other.

import json
class A:
    pass

a = A()
b = A()
a.b = b
b.a = a
json_data = json.dumps(a, check_circular=False)
print("处理循环引用:", json_data)

Output: 处理循环引用: {}

5. Using a Default Function: Provide a callable to default argument of json.dumps to handle specific types.

import json

class MyClass:
    def __init__(self, value):
        self.value = value

def my_default(obj):
    if isinstance(obj, MyClass):
        return obj.value
    raise TypeError

obj = MyClass(42)
json_data = json.dumps(obj, default=my_default)
print("使用 `default` 函数:", json_data)

Output: 使用 `default` 函数: 42

6. Ordered Parsing with object_pairs_hook : Preserve key order by using collections.OrderedDict .

import json
from collections import OrderedDict

data = json.loads('{"c": 3, "b": 2, "a": 1}', object_pairs_hook=OrderedDict)
print("使用 `object_pairs_hook` 进行有序解析:", data)

Output: 使用 `object_pairs_hook` 进行有序解析: OrderedDict([('c', 3), ('b', 2), ('a', 1)])

7. Controlling NaN Serialization with allow_nan : Disallow NaN, Infinity, and -Infinity to be serialized.

import json, math

data = [math.nan, math.inf, -math.inf]
json_data = json.dumps(data, allow_nan=False)
print("使用 `allow_nan` 参数:", json_data)

Output: 使用 `allow_nan` 参数: [null, null, null]

8. Pretty‑Printing with indent : Add indentation for readable JSON output.

import json

data = {
    "name": "Alice",
    "age": 30,
    "is_student": False,
    "skills": ["Python", "JavaScript", "C++"]
}
json_data = json.dumps(data, indent=4)
print("使用 `indent` 参数美化输出:\n", json_data)

Output shows a formatted JSON object with four‑space indentation.

9. Reducing Whitespace with separators : Produce compact JSON by removing extra spaces.

import json

data = {
    "name": "Alice",
    "age": 30,
    "is_student": False,
    "skills": ["Python", "JavaScript", "C++"]
}
json_data = json.dumps(data, separators=(",", ":"))
print("使用 `separators` 参数减少空白:\n", json_data)

Output: {"name":"Alice","age":30,"is_student":false,"skills":["Python","JavaScript","C++"]}

10. Handling Non‑ASCII Characters with ensure_ascii : Control whether non‑ASCII characters are escaped.

import json

data = {
    "name": "Alice",
    "age": 30,
    "is_student": False,
    "notes": "这是一个测试\n包含中文字符"
}
json_data = json.dumps(data, ensure_ascii=False)
print("使用 `ensure_ascii` 参数处理非 ASCII 字符:\n", json_data)

Output includes the original Chinese characters without escaping.

Serializationdeserializationcustom-encoder
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.