序列化为 JSON 数据数组 类

serializing to JSON an array of data classes

我有一个 数据数组 classes 我需要 序列化 到 JSON。我将列表包装在 class (Persons)

@attrs.frozen
class Person:
    name: str
    age: int
    grades: Dict[str, int]

@attrs.define
class Persons:
    persons: List[Person] = attrs.field(factory=list)
    def add(self, person: Person) -> None:
        self.persons.append(person)

def run(filename: str) -> None:

    college = Persons()
    college.add(Person("uzi" , 51, {"math": 100, "cs": 90}))
    college.add(Person("dave", 76, {"math": 94, "music": 92}))
    college.add(Person("dan",  22, {"bible": 98}))

    with open(filename, "w+") as fl:
        fl.write(f"{json.dumps(attrs.asdict(college), indent=4)}\n")

我能否以某种方式去掉包装 class 并仍然轻松地序列化 List[Person]

您可以使用 json.dumps 函数的 default 参数并传递函数 attrs.asdict 来序列化它。

我添加了“persons”键,使其与您的代码输出匹配。

import json
import attrs


@attrs.frozen
class Person:
    name: str
    age: int
    grades: dict[str, int]


def run(filename: str) -> None:

    college = []
    college.append(Person("uzi", 51, {"math": 100, "cs": 90}))
    college.append(Person("dave", 76, {"math": 94, "music": 92}))
    college.append(Person("dan", 22, {"bible": 98}))

    with open(filename, "w+") as fl:
        fl.write(
            f"{json.dumps({'persons': college}, default=attrs.asdict, indent=4)}\n"
        )


run("my_json.json")

输出

{
    "persons": [
        {
            "name": "uzi",
            "age": 51,
            "grades": {
                "math": 100,
                "cs": 90
            }
        },
        {
            "name": "dave",
            "age": 76,
            "grades": {
                "math": 94,
                "music": 92
            }
        },
        {
            "name": "dan",
            "age": 22,
            "grades": {
                "bible": 98
            }
        }
    ]
}

对于 dataclasses 的高级方法,我建议查看 dataclass-wizard 库。

它提供了一些通用且有用的实现,例如 Container 类型,它只是 Python.

list 类型的便利包装器

它还公开了有用的 mixin 类,这使得使用 YAML/JSON 文件更容易,如下所示。

from dataclasses import dataclass
from dataclass_wizard import Container, JSONListWizard, JSONFileWizard


# optional: extend from `JSONListWizard`, so de-serializing a list results
#   in a `Container` object; though you could also use `JSONWizard` instead.
#   also extend from `JSONFileWizard`, so we can de-serialize data back from
#   a JSON file.

@dataclass(frozen=True)
class Person(JSONListWizard, JSONFileWizard):
    name: str
    age: int
    grades: dict[str, int]


def run(filename: str) -> None:
    # create a `Container` object, which is just a wrapper around a Python `list`
    college = Container[Person]()

    college.append(Person("uzi", 51, {"math": 100, "cs": 90}))
    college.append(Person("dave", 76, {"math": 94, "music": 92}))
    college.append(Person("dan", 22, {"bible": 98}))

    # serialize the list of instances to a json file
    college.to_json_file(filename, indent=4)


run('my_file.json')

# now, read it back :-)
people = Person.from_json_file('my_file.json')

my_file.json 的内容如下所示:

[
    {
        "name": "uzi",
        "age": 51,
        "grades": {
            "math": 100,
            "cs": 90
        }
    },
    {
        "name": "dave",
        "age": 76,
        "grades": {
            "math": 94,
            "music": 92
        }
    },
    {
        "name": "dan",
        "age": 22,
        "grades": {
            "bible": 98
        }
    }
]