Search code examples
pythonjsonooppython-dataclassespython-class

How do I convert a json file to a python class?


Consider this json file named h.json I want to convert this into a python dataclass.

{
    "acc1":{
        "email":"acc1@example.com",
        "password":"acc1",
        "name":"ACC1",
        "salary":1
    },
    "acc2":{
        "email":"acc2@example.com",
        "password":"acc2",
        "name":"ACC2",
        "salary":2
    }

}

I could use an alternative constructor for getting each account, for example:

import json
from dataclasses import dataclass

@dataclass
class Account(object):
    email:str
    password:str
    name:str
    salary:int
    
    @classmethod
    def from_json(cls, json_key):
        file = json.load(open("h.json"))
        return cls(**file[json_key])

but this is limited to what arguments (email, name, etc.) were defined in the dataclass.

What if I were to modify the json to include another thing, say age? The script would end up returning a TypeError, specifically TypeError: __init__() got an unexpected keyword argument 'age'.

Is there a way to dynamically adjust the class attributes based on the keys of the dict (json object), so that I don't have to add attributes each time I add a new key to the json?


Solution

  • This way you lose some dataclass features.

    • Such as determining whether it is optional or not
    • Such as auto-completion feature

    However, you are more familiar with your project and decide accordingly

    There must be many methods, but this is one of them:

    @dataclass
    class Account(object):
        email: str
        password: str
        name: str
        salary: int
    
        @classmethod
        def from_json(cls, json_key):
            file = json.load(open("1.txt"))
            keys = [f.name for f in fields(cls)]
            # or: keys = cls.__dataclass_fields__.keys()
            json_data = file[json_key]
            normal_json_data = {key: json_data[key] for key in json_data if key in keys}
            anormal_json_data = {key: json_data[key] for key in json_data if key not in keys}
            tmp = cls(**normal_json_data)
            for anormal_key in anormal_json_data:
                setattr(tmp,anormal_key,anormal_json_data[anormal_key])
            return tmp
    
    test = Account.from_json("acc1")
    print(test.age)