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.

在此先感谢您的帮助。

您希望编码器同时支持 Decimaldataclass。你可以这样做:

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"]}]}