让类实现JSON序列化的方法

让类实现JSON序列化的方法

技术背景

在Python开发中,JSON(JavaScript Object Notation)是一种常用的数据交换格式。然而,Python中的自定义类对象不能直接被json模块序列化。因此,我们需要找到一些方法来实现自定义类的JSON序列化,以便在不同系统之间交换数据。

实现步骤

1. .toJSON() 方法

实现一个序列化方法,而不是直接让类成为JSON可序列化的。示例代码如下:

1
2
3
4
5
6
7
8
9
import json

class Object:
def toJSON(self):
return json.dumps(
self,
default=lambda o: o.__dict__,
sort_keys=True,
indent=4)

使用示例:

1
2
3
4
5
6
7
me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"

print(me.toJSON())

2. 使用 orjson

orjson 是一个功能强大的JSON处理库,可以直接使用。示例代码如下:

1
2
3
4
5
6
7
8
9
10
import orjson

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

obj = MyClass("John", 30)
json_data = orjson.dumps(obj.__dict__)
print(json_data)

3. 自定义 JSONEncoder

通过继承 JSONEncoder 类,实现自定义的序列化逻辑。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import json

class ObjectEncoder(json.JSONEncoder):
def default(self, obj):
if hasattr(obj, "__dict__"):
return obj.__dict__
return json.JSONEncoder.default(self, obj)

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

obj = MyClass("John", 30)
json_data = json.dumps(obj, cls=ObjectEncoder)
print(json_data)

4. 使用 jsonpickle

jsonpickle 可以处理更复杂的Python对象的序列化和反序列化。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
import jsonpickle

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

obj = MyClass("John", 30)
json_string = jsonpickle.encode(obj)
print(json_string)

recreated_obj = jsonpickle.decode(json_string)
print(recreated_obj.name, recreated_obj.age)

5. 继承 dict

如果类只是简单的数据表示,可以继承 dict 类。示例代码如下:

1
2
3
4
5
6
7
8
9
import json

class FileItem(dict):
def __init__(self, fname):
dict.__init__(self, fname=fname)

f = FileItem('tasks.txt')
json_data = json.dumps(f)
print(json_data)

6. 使用 jsons

jsons 可以将对象(及其所有属性)递归地转换为字典。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
import jsons

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

obj = MyClass("John", 30)
a_dict = jsons.dump(obj)
print(a_dict)

a_str = jsons.dumps(obj)
print(a_str)

7. 包装JSON转储逻辑

将JSON转储逻辑封装在类中。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
import json

class FileItem:
def __init__(self, fname: str) -> None:
self.fname = fname

def __repr__(self) -> str:
return json.dumps(self.__dict__)

f = FileItem('/foo/bar')
print(f)

8. 自定义序列化函数

使用自定义函数处理序列化。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import json

def dumper(obj):
try:
return obj.toJSON()
except:
return obj.__dict__

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

obj = MyClass("John", 30)
json_data = json.dumps(obj, default=dumper, indent=2)
print(json_data)

9. 使用 json-tricks

json-tricks 可以处理复杂对象的序列化和反序列化。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from json_tricks import dumps, loads

class MyClass:
def __init__(self, relevant):
self.relevant = relevant
self.irrelevant = 37

def __json_encode__(self):
return {'relevant': self.relevant}

def __json_decode__(self, **attrs):
self.relevant = attrs['relevant']
self.irrelevant = 12

obj = MyClass(42)
json_str = dumps(obj, indent=4)
print(json_str)

recreated_obj = loads(json_str)
print(recreated_obj.relevant)

10. 自定义序列化方法

通过定义 __json__ 方法实现自定义序列化。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import json

def _default(self, obj):
return getattr(obj.__class__, "__json__", _default.default)(obj)

_default.default = json.JSONEncoder().default
json.JSONEncoder.default = _default

class MyClass:
def __json__(self):
return {'name': 'John', 'age': 30}

obj = MyClass()
json_data = json.dumps(obj)
print(json_data)

核心代码

以下是一个综合示例,展示了如何使用自定义 JSONEncoder 处理嵌套对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import json
import inspect

class ObjectEncoder(json.JSONEncoder):
def default(self, obj):
if hasattr(obj, "to_json"):
return self.default(obj.to_json())
elif hasattr(obj, "__dict__"):
d = dict(
(key, value)
for key, value in inspect.getmembers(obj)
if not key.startswith("__")
and not inspect.isabstract(value)
and not inspect.isbuiltin(value)
and not inspect.isfunction(value)
and not inspect.isgenerator(value)
and not inspect.isgeneratorfunction(value)
and not inspect.ismethod(value)
and not inspect.ismethoddescriptor(value)
and not inspect.isroutine(value)
)
return self.default(d)
return obj

class C(object):
c = "NO"
def to_json(self):
return {"c": "YES"}

class B(object):
b = "B"
i = "I"
def __init__(self, y):
self.y = y

def f(self):
print("f")

class A(B):
a = "A"
def __init__(self):
self.b = [{"ab": B("y")}]
self.c = C()

print(json.dumps(A(), cls=ObjectEncoder, indent=2, sort_keys=True))

最佳实践

  • 选择合适的方法:根据类的复杂度和具体需求选择合适的序列化方法。对于简单类,继承 dict 或实现 toJSON 方法可能足够;对于复杂类,使用 jsonpickle 或自定义 JSONEncoder 更合适。
  • 处理特殊类型:对于 datetimeEnum 等特殊类型,需要在序列化时进行特殊处理。
  • 考虑性能:如果对性能要求较高,可以选择 orjson 等高性能库。

常见问题

1. TypeError: Object of type '...' is not JSON serializable

这通常是因为对象不能直接被 json 模块序列化。可以使用上述方法之一进行处理,如自定义 JSONEncoder 或使用 jsonpickle

2. 序列化时丢失某些属性

在自定义序列化方法时,可能会遗漏某些属性。确保在序列化时包含所有需要的属性。

3. 反序列化问题

在反序列化时,可能会遇到类型转换或数据丢失的问题。确保在反序列化时正确处理这些问题,如使用自定义的 object_hook 方法。


让类实现JSON序列化的方法
https://119291.xyz/posts/make-class-json-serializable-guide/
作者
ww
发布于
2025年6月23日
许可协议