Consider the json (named h.json
), want to convert this into a python dataclass.
{
"acc1":{
"email":"[email protected]",
"password":"acc1",
"name":"ACC1",
"salary":1
},
"acc2":{
"email":"[email protected]",
"password":"acc2",
"name":"ACC2",
"salary":2
}
}
I could always 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.
(PS: I'm new to python, coding in general)
CodePudding user response:
For a flat (not nested dataclass) the code below does the job.
If you need to handle nested dataclasses you should use a framework like dacite
.
Note 1 that loading the data from the json file should not be part of your class logic.
Note 2 If your json can contain anything - you can not map it to a dataclass and you should have to work with a dict
from dataclasses import dataclass
from typing import List
data = {
"acc1":{
"email":"[email protected]",
"password":"acc1",
"name":"ACC1",
"salary":1
},
"acc2":{
"email":"[email protected]",
"password":"acc2",
"name":"ACC2",
"salary":2
}
}
@dataclass
class Account:
email:str
password:str
name:str
salary:int
accounts: List[Account] = [Account(**x) for x in data.values()]
print(accounts)
output
[Account(email='[email protected]', password='acc1', name='ACC1', salary=1), Account(email='[email protected]', password='acc2', name='ACC2', salary=2)]
CodePudding user response:
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 = 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)