python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python JSON解码器

Python自定义实现JSON解码器的完整指南

作者:青禾837

本文主要为大家详细介绍了如何通过继承JSONDecoder并重写decode()方法实现自定义JSON反序列化,将JSON字符串精准还原为Python对象,文中的示例代码讲解详细,有需要的小伙伴可以了解下

大家好,在之前的文章中,我们系统性地讲解了自定义 JSON 编码器(JSONEncoder)的实现。今天我们将聚焦于它的"逆向工程"——通过继承 JSONDecoder 并重写 decode() 方法来实现自定义 JSON 反序列化,将 JSON 字符串精准还原为 Python 对象。同时,我们还会结合多继承的案例,展示如何将序列化能力灵活组合到类体系中。

一、JSONDecoder 与 decode 方法概述

1.1 为什么需要自定义解码器

json.loads() 默认将 JSON 解析为字典、列表等基础类型,无法自动还原为自定义类实例:

import json
json_str = '{"name": "张三", "age": 25}'
data = json.loads(json_str)
print(type(data))   # <class 'dict'>

我们期望的是:

# 自动还原为 Person 对象
person = json.loads(json_str, cls=PersonDecoder)
print(person.name)   # 张三

1.2 JSONDecoder 的核心方法

方法说明
__init__()构造方法,可传入 object_hookparse_float 等参数
decode(s)核心方法:将 JSON 字符串解析为 Python 对象
raw_decode(s)底层解析方法,返回 (对象, 索引) 元组

自定义解码器的实现方式:

重写 decode() 方法 —— 完全控制解析流程

二、重写 decode 方法

2.1 基础实现

import json
from datetime import datetime
from typing import Any

class Person:
    def __init__(self, name: str, age: int, created_at: datetime = None):
        self.name = name
        self.age = age
        self.created_at = created_at or datetime.now()
    
    def __repr__(self):
        return f"Person(name={self.name}, age={self.age}, created_at={self.created_at})"


class PersonEncoder(json.JSONEncoder):
    """序列化编码器"""
    def default(self, obj):
        if isinstance(obj, Person):
            return {
                "__type__": "Person",
                "name": obj.name,
                "age": obj.age,
                "created_at": obj.created_at.isoformat()
            }
        if isinstance(obj, datetime):
            return {"__type__": "datetime", "value": obj.isoformat()}
        return super().default(obj)


class PersonDecoder(json.JSONDecoder):
    """自定义解码器:重写 decode 方法"""
    
    def decode(self, s: str) -> Any:
        """解析 JSON 字符串,还原为 Person 对象"""
        # 先调用父类方法解析为 Python 字典
        data = super().decode(s)
        return self._convert(data)
    
    def _convert(self, data):
        """递归转换数据"""
        if isinstance(data, dict):
            # 检查类型标识
            if data.get("__type__") == "Person":
                created_at = data.get("created_at")
                if created_at:
                    created_at = datetime.fromisoformat(created_at)
                return Person(
                    name=data["name"],
                    age=data["age"],
                    created_at=created_at
                )
            if data.get("__type__") == "datetime":
                return datetime.fromisoformat(data["value"])
            # 递归处理字典中的每个值
            return {k: self._convert(v) for k, v in data.items()}
        
        elif isinstance(data, list):
            # 递归处理列表中的每个元素
            return [self._convert(item) for item in data]
        
        return data


# 测试
p = Person("张三", 25)
json_str = json.dumps(p, cls=PersonEncoder, ensure_ascii=False)
print("序列化:", json_str)

restored = json.loads(json_str, cls=PersonDecoder)
print("还原:", restored)
print("类型:", type(restored))
print("姓名:", restored.name)
print("创建时间类型:", type(restored.created_at))

输出

序列化: {"__type__": "Person", "name": "张三", "age": 25, "created_at": "2024-01-15T10:30:00.123456"}
还原: Person(name=张三, age=25, created_at=2024-01-15 10:30:00.123456)
类型: <class '__main__.Person'>
姓名: 张三
创建时间类型: <class 'datetime.datetime'>

2.2 支持多种类型

class Address:
    def __init__(self, city: str, district: str):
        self.city = city
        self.district = district
    
    def __repr__(self):
        return f"Address(city={self.city}, district={self.district})"

class Student:
    def __init__(self, name: str, age: int, address: Address = None):
        self.name = name
        self.age = age
        self.address = address
    
    def __repr__(self):
        return f"Student(name={self.name}, age={self.age}, address={self.address})"


class MultiDecoder(json.JSONDecoder):
    """支持多种类型的解码器"""
    
    def decode(self, s: str) -> Any:
        data = super().decode(s)
        return self._convert(data)
    
    def _convert(self, data):
        if isinstance(data, dict):
            obj_type = data.get("__type__")
            
            if obj_type == "Person":
                return Person(
                    name=data["name"],
                    age=data["age"],
                    created_at=self._convert(data.get("created_at"))
                )
            
            if obj_type == "Student":
                return Student(
                    name=data["name"],
                    age=data["age"],
                    address=self._convert(data.get("address"))
                )
            
            if obj_type == "Address":
                return Address(
                    city=data["city"],
                    district=data["district"]
                )
            
            if obj_type == "datetime":
                return datetime.fromisoformat(data["value"])
            
            # 递归处理
            return {k: self._convert(v) for k, v in data.items()}
        
        elif isinstance(data, list):
            return [self._convert(item) for item in data]
        
        return data


class MultiEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Person):
            return {"__type__": "Person", "name": obj.name, "age": obj.age, "created_at": obj.created_at}
        if isinstance(obj, Student):
            return {"__type__": "Student", "name": obj.name, "age": obj.age, "address": obj.address}
        if isinstance(obj, Address):
            return {"__type__": "Address", "city": obj.city, "district": obj.district}
        if isinstance(obj, datetime):
            return {"__type__": "datetime", "value": obj.isoformat()}
        return super().default(obj)


# 测试
addr = Address("北京", "朝阳区")
student = Student("李四", 20, addr)
json_str = json.dumps(student, cls=MultiEncoder, ensure_ascii=False, indent=2)
print("序列化:")
print(json_str)

restored = json.loads(json_str, cls=MultiDecoder)
print("\n还原:")
print(restored)
print(restored.address.city)

三、继承序列化类 + 多继承实战

将序列化能力封装到基类中,通过多继承组合到业务类。

序列化基类与混合类

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

    def __str__(self):
        return f"name:{self.name},age:{self.age}"

class Animal(Life):
    def __init__(self,name,age,speed):
        super().__init__(name,age)
        self.speed = speed

    def __str__(self):
        return f"{super().__str__()},speed:{self.speed}"

class Flyable:
    def fly(self):
        return f"{self.name}正在飞行,速度为{self.speed}"

class SwimAble:
    def swim(self):
        return f"{self.name}正在游泳,速度为{self.speed}"
class AttackAble:
    def attack(self):
        return f"{self.name}会攻击,破坏力强大"

class Bird(Flyable,Animal,Life,AttackAble):
    def __init__(self,name,age,speed):
        super().__init__(name,age,speed)

    def speek(self):
        return f"{self.name}正在喳喳喳"

class Dog(Animal,Life,SwimAble,AttackAble):
    def __init__(self,name,age,speed):
        super().__init__(name,age,speed)

    def speek(self):
        return f"{self.name}正在汪汪汪"

class BigSwan(Animal,Life,SwimAble,Flyable,AttackAble):
    def __init__(self,name,age,speed):
        super().__init__(name,age,speed)

    def speek(self):
        return f"{self.name}发出鹅鹅鹅的声音"

l0 = Life("张飞",18)
print(l0)
a0 = Animal("陈军",18,30)
print(a0)
b1 = Bird("刘振阳",18,100)
print(b1,b1.speek(),b1.fly(),b1.attack())
d1 = Dog("陈军",18,30)
print(d1,d1.speek(),d1.swim(),d1.attack())
bs = BigSwan("张怡飞",20,50)
print(bs,bs.speek(),bs.swim(),bs.fly(),bs.attack())

四、总结

知识点核心要点
JSONDecoder自定义解码器的基类,通过继承实现定制
decode() 方法重写后可完全控制解析流程,实现递归转换
类型标识 __type__标记对象的原始类型,便于反序列化还原
递归转换处理嵌套对象时需要递归调用转换逻辑
类型注册表集中管理类型映射,使解码器可扩展
多继承组合通过 SerializableMixin + DeserializableMixin 组合序列化能力

继承 JSONDecoder 并重写 decode() 方法是实现自定义反序列化的核心方式,而 object_hook 则提供了更简洁的替代方案。将序列化能力封装到基类或混合类中,配合类型注册机制,可以构建出灵活、可扩展的序列化体系,在实际项目中非常实用。

到此这篇关于Python自定义实现JSON解码器的完整指南的文章就介绍到这了,更多相关Python JSON解码器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文