Python:将 class 对象转换为 JSON - 对象不可 JSON 序列化
Python: converting class objects to JSON - object is not JSON serializable
我的 Python 代码中有一个对象列表。每个对象都是具有关联的内部对象的外部类型 - 类 定义如下:
from decimal import Decimal
@dataclass
class Inner:
col_a: Decimal
col_b: str
col_c: List['str']
@dataclass
class Outer:
col_a: str
col_b: Decimal
col_c: List[Inner]
我想将这些对象转换成 JSON。当我使用 Decimal 时,我希望只创建自己的编码器并将其与 json.dumps():
结合使用
class DecimalJsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Decimal):
return str(obj)
else:
return super(DecimalJsonEncoder, self).default(obj)
...和...
my_json = json.dumps(my_list, cls=DecimalJsonEncoder)
但是,当我创建外部对象列表 (my_list) 并尝试创建 JSON 时,出现此错误:
TypeError: Object of type Outer is not JSON serializable
我正在使用 Python 3.7.
在此先感谢您的帮助。
您希望编码器同时支持 Decimal
和 dataclass
。你可以这样做:
import dataclasses, json
class JSONEncoder(json.JSONEncoder):
def default(self, o):
if dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
if isinstance(obj, Decimal):
return str(obj)
return super().default(o)
json.dumps(foo, cls=JSONEncoder)
只需添加一个适合您的替代解决方案。如果您需要反序列化(加载)JSON 数据返回到嵌套数据类模型,这将特别有用。
这使用外部库 dataclass-wizard,它是一个构建在数据类之上的 JSON 序列化框架。下面的示例应该适用于 Python 3.7+ 包含的 __future__
导入。
from __future__ import annotations
from dataclasses import dataclass
from decimal import Decimal
from dataclass_wizard import JSONWizard
@dataclass
class Outer(JSONWizard, str=False):
col_a: str
col_b: Decimal
col_c: list[Inner]
@dataclass
class Inner:
col_a: Decimal
col_b: str
col_c: list[str]
def main():
obj = Outer(col_a='abc',
col_b=Decimal('1.23'),
col_c=[Inner(col_a=Decimal('3.21'),
col_b='xyz',
col_c=['blah', '1111'])])
print(obj)
print(obj.to_json())
# {"colA": "abc", "colB": "1.23", "colC": [{"colA": "3.21", "colB": "xyz", "colC": ["blah", 1111]}]}
# assert we get the same object when de-serializing the string data
assert obj == obj.from_dict(obj.to_dict())
if __name__ == '__main__':
main()
输出:
Outer(col_a='abc', col_b=Decimal('1.23'), col_c=[Inner(col_a=Decimal('3.21'), col_b='xyz', col_c=['blah', '1111'])])
{"colA": "abc", "colB": "1.23", "colC": [{"colA": "3.21", "colB": "xyz", "colC": ["blah", "1111"]}]}
我的 Python 代码中有一个对象列表。每个对象都是具有关联的内部对象的外部类型 - 类 定义如下:
from decimal import Decimal
@dataclass
class Inner:
col_a: Decimal
col_b: str
col_c: List['str']
@dataclass
class Outer:
col_a: str
col_b: Decimal
col_c: List[Inner]
我想将这些对象转换成 JSON。当我使用 Decimal 时,我希望只创建自己的编码器并将其与 json.dumps():
结合使用class DecimalJsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Decimal):
return str(obj)
else:
return super(DecimalJsonEncoder, self).default(obj)
...和...
my_json = json.dumps(my_list, cls=DecimalJsonEncoder)
但是,当我创建外部对象列表 (my_list) 并尝试创建 JSON 时,出现此错误:
TypeError: Object of type Outer is not JSON serializable
我正在使用 Python 3.7.
在此先感谢您的帮助。
您希望编码器同时支持 Decimal
和 dataclass
。你可以这样做:
import dataclasses, json
class JSONEncoder(json.JSONEncoder):
def default(self, o):
if dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
if isinstance(obj, Decimal):
return str(obj)
return super().default(o)
json.dumps(foo, cls=JSONEncoder)
只需添加一个适合您的替代解决方案。如果您需要反序列化(加载)JSON 数据返回到嵌套数据类模型,这将特别有用。
这使用外部库 dataclass-wizard,它是一个构建在数据类之上的 JSON 序列化框架。下面的示例应该适用于 Python 3.7+ 包含的 __future__
导入。
from __future__ import annotations
from dataclasses import dataclass
from decimal import Decimal
from dataclass_wizard import JSONWizard
@dataclass
class Outer(JSONWizard, str=False):
col_a: str
col_b: Decimal
col_c: list[Inner]
@dataclass
class Inner:
col_a: Decimal
col_b: str
col_c: list[str]
def main():
obj = Outer(col_a='abc',
col_b=Decimal('1.23'),
col_c=[Inner(col_a=Decimal('3.21'),
col_b='xyz',
col_c=['blah', '1111'])])
print(obj)
print(obj.to_json())
# {"colA": "abc", "colB": "1.23", "colC": [{"colA": "3.21", "colB": "xyz", "colC": ["blah", 1111]}]}
# assert we get the same object when de-serializing the string data
assert obj == obj.from_dict(obj.to_dict())
if __name__ == '__main__':
main()
输出:
Outer(col_a='abc', col_b=Decimal('1.23'), col_c=[Inner(col_a=Decimal('3.21'), col_b='xyz', col_c=['blah', '1111'])])
{"colA": "abc", "colB": "1.23", "colC": [{"colA": "3.21", "colB": "xyz", "colC": ["blah", "1111"]}]}