Created
February 19, 2019 15:08
-
-
Save gatopeich/1efd3e1e4269e1e98fae9983bb914f22 to your computer and use it in GitHub Desktop.
Python 3.7 dataclass to/from dict/json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from dataclasses import dataclass, fields as datafields | |
from ujson import dumps, loads | |
# Note: ujson seamlessly serializes dataclasses, unlike stdlib's json | |
@dataclass | |
class Point: | |
x: float | |
y: float | |
# Shallow dataclass can be rebuilt from dict/json: | |
point = Point(1,2) | |
assert point == Point(**loads(dumps(point))) | |
# However, deep dataclass's fields won't be rebuilt from the json dict: | |
@dataclass | |
class Line: | |
a: Point | |
b: Point | |
line = Line(Point(1,2), Point(3,4)) | |
assert line != Line(**loads(dumps(line))) | |
print(line, '\n !=', Line(**loads(dumps(line)))) | |
# Line(a=Point(x=1, y=2), b=Point(x=3, y=4)) | |
# != Line(a={'x': 1, 'y': 2}, b={'x': 3, 'y': 4}) | |
# But we can simply reconstruct recursively: | |
def dataclass_from_dict(klass, dikt): | |
try: | |
fieldtypes = {f.name:f.type for f in datafields(klass)} | |
return klass(**{f:dataclass_from_dict(fieldtypes[f],dikt[f]) for f in dikt}) | |
except: | |
return dikt | |
line_from_dict = dataclass_from_dict(Line,loads(dumps(line))) | |
assert line == line_from_dict |
@EnlNovius Thanks, I've missed the d
. Also using AttributeError
makes probably more sense, cannot think of any potential problem.
Using annotations you remove all inherited fields
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think your solution is good. I would just change the type of the exception (and by the way correct the d by dikt in the exception).