Starting with Python 3.7, there is something called a dataclass:
from dataclasses import dataclass
@dataclass
class Foo:
x: str
However, t
If you are ok with using a library for that, you can use dataclasses-json. Here is an example:
from dataclasses import dataclass
from dataclasses_json import dataclass_json
@dataclass_json
@dataclass
class Foo:
x: str
foo = Foo(x="some-string")
foo_json = foo.to_json()
It also supports embedded dataclasses - if your dataclass has a field typed as another dataclass - if all dataclasses envolved have the @dataclass_json
decorator.
I'd suggest creating a parent class for your dataclasses with a to_json()
method:
import json
from dataclasses import dataclass, asdict
@dataclass
class Dataclass:
def to_json(self) -> str:
return json.dumps(asdict(self))
@dataclass
class YourDataclass(Dataclass):
a: int
b: int
x = YourDataclass(a=1, b=2)
x.to_json() # '{"a": 1, "b": 2}'
This is especially useful if you have other functionality to add to all your dataclasses.
Can't you just use the dataclasses.asdict()
function to convert the dataclass
to a dict? Something like:
>>> @dataclass
... class Foo:
... a: int
... b: int
...
>>> x = Foo(1,2)
>>> json.dumps(dataclasses.asdict(x))
'{"a": 1, "b": 2}'
A much simpler answer can be found on Reddit using dictionary unpacking
>>> from dataclasses import dataclass
>>> @dataclass
... class MyData:
... prop1: int
... prop2: str
... prop3: int
...
>>> d = {'prop1': 5, 'prop2': 'hi', 'prop3': 100}
>>> my_data = MyData(**d)
>>> my_data
MyData(prop1=5, prop2='hi', prop3=100)
There are couple of options to accomplish that goal, selection of each imply analyze on which approach suits best for your needs:
import dataclasses
import json
@dataclass.dataclass
class Foo:
x: str
foo = Foo(x='1')
json_foo = json.dumps(dataclasses.asdict(foo)) # '{"x": "1"}'
Picking it back to dataclass instance isn't trivial, so you may want to visit that answer https://stackoverflow.com/a/53498623/2067976
from dataclasses import field
from marshmallow_dataclass import dataclass
@dataclass
class Foo:
x: int = field(metadata={"required": True})
foo = Foo(x='1') # Foo(x='1')
json_foo = foo.Schema().dumps(foo) # '{"x": "1"}'
# Back to class instance.
Foo.Schema().loads(json_foo) # Foo(x=1)
As a bonus for marshmallow_dataclass
you may use validation on the field itself, that validation will be used when someone deserialize the object from json using that schema.
from dataclasses import dataclass
from dataclasses_json import dataclass_json
@dataclass_json
@dataclass
class Foo:
x: int
foo = Foo(x='1')
json_foo = foo.to_json() # Foo(x='1')
# Back to class instance
Foo.from_json(json_foo) # Foo(x='1')
Also, in addition to that notice that marshmallow dataclass did type conversion for you whereas dataclassses-json(ver.: 0.5.1) ignores that.
Follow accepted miracle2k answer and reuse custom json encoder.
Much like you can add support to the JSON encoder for datetime objects or Decimals, you can also provide a custom encoder subclass to serialize dataclasses:
import dataclasses, json
class EnhancedJSONEncoder(json.JSONEncoder):
def default(self, o):
if dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
return super().default(o)
json.dumps(foo, cls=EnhancedJSONEncoder)