Python自定义实现JSON解码器的完整指南
大家好,在之前的文章中,我们系统性地讲解了自定义 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_hook、parse_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解码器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
将Jupyter Notebook(.ipynb)文件转换为Python(.py)文件的3种方法
大多数数据科学在线课程都把Jupyter Notebook作为教学媒介,这是因为初学者在Jupyter Notebook的单元格中编写代码,比编写包含类和函数的脚本更容易,这篇文章主要给大家介绍了关于将Jupyter Notebook(.ipynb)文件转换为Python(.py)文件的3种方法,需要的朋友可以参考下2023-10-10
python数据可视化 – 利用Bokeh和Bottle.py在网页上展示你的数据
本文将展示如何使用python搭建一个网页应用来展示你的数据图表 很多有关于使用python搭建网页应用的文章聚焦在如何教读者搭建一个网页应用(大多是博客),很多关于使用python做数据可视化的文章聚焦在如何教读者使用python的图表库来做可视化2021-10-10


最新评论