Reputation: 173
I have a simple class and JSON :
@dataclass
class Point:
x: int
y: int
jsonString = '{"x": 3, "y": 5}'
I want to convert the JSON data to an instance of a point. from C# it's easy :
JsonConvert.DeserializeObject<Point>(jsonString);
How I can do it in Python?
Upvotes: 2
Views: 5102
Reputation: 10564
I was doing json schema validation elsewhere so something simple like this worked for me:
point = Point(**json.loads(jsonString))
Upvotes: 4
Reputation: 123463
If the "simple class" is implemented a dataclass
, as shown in your question, the JSON data could be deserialized with the generic deserialize_dataclass
function shown below.
dataclasses
make it fairly easy to introspect the decorated classes and the information can be used extract and convert the JSON object represented by the string.
import dataclasses
import json
dataclass = dataclasses.dataclass
def deserialize_dataclass(DataClass, json_string):
""" Convert the JSON object represented by the string into the dataclass
specified.
"""
json_obj = json.loads(json_string)
dc_data = {field.name: field.type(json_obj[field.name])
for field in dataclasses.fields(DataClass)}
return DataClass(**dc_data)
@dataclass
class Point:
x: int
y: int
json_string = '{"x": "3", "y": "5"}'
pt = deserialize_dataclass(Point, json_string)
print(pt) # -> Point(x=3, y=5)
Upvotes: -1
Reputation: 531155
You can use a generator expression to consume the appropriate values,
by decoding the string then iterating over the values corresponding to x
and y
.
>>> from operator import itemgetter
>>> coords = itemgetter('x', 'y')
>>> Point(*(int(x) for x in coords(json.loads(jsonString))))
Point(x=3, y=5)
coords
is a function that returns a tuple consisting of its argument's x
and y
values. The generator expression ensures each value is converted to an int
, and the *
syntax unpacks the generator into individual arguments.
A more idiomatic solution, though, would be to define a class method to construct a Point
given an appropriate object:
@dataclass
class Point:
x: int
y: int
@classmethod
def from_dict(cls, d):
return cls(d['x'], d['y'])
p = Point.from_dict(json.loads(jsonString))
You could also define a from_json
class method to wrap from_dict
:
@dataclass
class Point:
x: int
y: int
@classmethod
def from_dict(cls, d):
return cls(d['x'], d['y'])
@classmethod
def from_json(cls, j):
return cls.from_dict(json.loads(j))
p = Point.from_json(jsonString)
Though not shown here, the class methods provide places to do validation of the passed JSON string or argument, so you can more gracefully handle things like missing keys, extra keys, JSON values that aren't objects, etc.
Upvotes: 1
Reputation: 3527
How about something like this?
EDIT: you can also convert x and y to ints if they are initially strings:
# define Point class:
class Point():
# define init function:
def __init__(self, data):
self.x = int(data['x'])
self.y = int(data['y'])
# your json point:
json_data = {'x' : '2', 'y' : '3'}
# convert to Point class:
my_point = Point(json_data)
print(my_point)
print(my_point.x)
print(my_point.y)
Upvotes: -1