Search code examples
pythonjsonserializationpython-attrs

serializing to JSON an array of data classes


I have an array of data classes I need to serialize to JSON. I wrap the list in a 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")

Can I somehow get rid of the wrapping class and still serialize a List[Person] easily?


Solution

  • You can use default argument of the json.dumps function and pass the function attrs.asdict to serialize it.

    I have added the "persons" key so it matches the output of your code.

    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")
    

    Output

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