如何使Python类可JSON序列化

如何使Python类可JSON序列化

技术背景

在Python开发中,JSON(JavaScript Object Notation)是一种常用的数据交换格式。然而,Python的json模块默认只能序列化一些基本数据类型,如字典、列表、字符串、整数等。当我们需要将自定义类的实例转换为JSON格式时,就会遇到TypeError: Object of type 'Classname' is not JSON serializable的错误。因此,需要找到方法使自定义类可JSON序列化。

实现步骤

1. 使用toJSON方法

实现一个序列化方法toJSON,在方法中使用json.dumpslambda函数将对象的__dict__属性转换为JSON字符串。

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

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

me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"

print(me.toJSON())

2. 自定义JSONEncoder

创建一个继承自JSONEncoder的类,并重写default方法,在方法中返回对象的__dict__属性。然后将这个类作为cls参数传递给json.dumps

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

class MyEncoder(JSONEncoder):
def default(self, o):
return o.__dict__

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

f = FileItem("/foo/bar")
print(MyEncoder().encode(f))

3. 使用jsonpickle

jsonpickle是一个用于将复杂Python对象序列化和反序列化的库。使用jsonpickle.encode将对象转换为JSON字符串,使用jsonpickle.decode将JSON字符串转换为Python对象。

1
2
3
4
5
6
7
8
9
import jsonpickle

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

x = FileItem('/foo/bar')
json_string = jsonpickle.encode(x)
recreated_obj = jsonpickle.decode(json_string)

4. 继承自dict

让类继承自dict,并在__init__方法中初始化字典的键值对。这样,该类的实例就可以直接被json.dumps序列化。

1
2
3
4
5
6
class FileItem(dict):
def __init__(self, fname):
dict.__init__(self, fname=fname)

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

5. 使用vars函数

vars函数作为default参数传递给json.dumpsvars函数会将对象转换为包含其所有属性的字典。

1
2
3
4
5
6
class FileItem:
def __init__(self, fname):
self.fname = fname

x = FileItem('/foo/bar')
print(json.dumps(x, default=vars))

核心代码

以下是几种常见方法的核心代码示例:

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
46
47
48
49
50
51
52
53
54
import json
from json import JSONEncoder
import jsonpickle

# 方法1:使用toJSON方法
class Object:
def toJSON(self):
return json.dumps(
self,
default=lambda o: o.__dict__,
sort_keys=True,
indent=4)

# 方法2:自定义JSONEncoder
class MyEncoder(JSONEncoder):
def default(self, o):
return o.__dict__

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

# 方法3:使用jsonpickle库
class AnotherFileItem:
def __init__(self, fname):
self.fname = fname

# 方法4:继承自dict
class DictFileItem(dict):
def __init__(self, fname):
dict.__init__(self, fname=fname)

# 方法5:使用vars函数
class VarsFileItem:
def __init__(self, fname):
self.fname = fname

# 测试代码
me = Object()
me.name = "Onur"
print(me.toJSON())

f = FileItem("/foo/bar")
print(MyEncoder().encode(f))

x = AnotherFileItem('/foo/bar')
json_string = jsonpickle.encode(x)
print(json_string)

d = DictFileItem('tasks.txt')
print(json.dumps(d))

v = VarsFileItem('/foo/bar')
print(json.dumps(v, default=vars))

最佳实践

  • 简单对象:如果对象结构简单,使用vars函数或继承自dict是比较简单直接的方法。
  • 复杂对象:对于包含嵌套对象或需要自定义序列化逻辑的复杂对象,建议使用jsonpickle库或自定义JSONEncoder
  • 兼容性:如果需要在不同的Python版本或项目中使用,选择标准库提供的方法(如自定义JSONEncoder)可以保证兼容性。

常见问题

1. __dict__不包含所有属性

如果对象使用了__slots__或者某些属性没有在__init__中初始化,__dict__可能不包含所有属性。可以通过自定义序列化逻辑来处理这种情况。

2. 嵌套对象序列化问题

使用__dict__vars函数时,嵌套对象可能无法正确序列化。可以使用递归的方式处理嵌套对象,或者使用jsonpickle库来自动处理。

3. 第三方库调用json.dumps

如果无法控制json.dumps的调用(如在第三方库中使用),可以通过继承自dict或使用json-fix模块来解决。


如何使Python类可JSON序列化
https://119291.xyz/posts/2025-04-22.how-to-make-python-class-json-serializable/
作者
ww
发布于
2025年4月22日
许可协议