使Python json编码器支持Python的新数据类

时间:2018-07-11 13:29:38

标签: python python-dataclasses

从Python 3.7开始,有一种叫做数据类的东西:

from dataclasses import dataclass

@dataclass
class Foo:
    x: str

但是,以下操作失败:

>>> import json
>>> foo = Foo(x="bar")
>>> json.dumps(foo)
TypeError: Object of type Foo is not JSON serializable

如何使json.dumps()的{​​{1}}实例编码为json objects

7 个答案:

答案 0 :(得分:16)

就像您可以为datetime objects或Decimals添加对JSON编码器的支持一样,您还可以提供自定义编码器子类来序列化数据类:

Foo

答案 1 :(得分:10)

如果可以使用该库,则可以使用dataclasses-json。这是一个示例:

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()

它还支持嵌入式数据类-如果您的数据类具有键入为另一个数据类的字段-如果所涉及的所有数据类都具有@dataclass_json装饰器。

答案 2 :(得分:10)

获取JSONized数据类实例的方式

要实现该目标,有两种选择,每种选择都暗示着哪种方法最适合您的需求:

Standart library: dataclass.asdict

import dataclasses
import json


@dataclass.dataclass
class Foo:
    x: str

foo = Foo(x='1')
json_foo = json.dumps(dataclasses.asdict(foo)) # '{"x": "1"}'

将其选择回数据类实例并非易事,因此您可能希望访问该答案https://stackoverflow.com/a/53498623/2067976

Marshmallow Dataclass

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)

作为marshmallow_dataclass的奖励,您可以在字段本身上使用验证,当有人使用该模式从json反序列化对象时,将使用该验证。

Dataclasses Json

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')

此外,除了这一点,棉花糖数据类确实为您进行了类型转换,而dataclassses-json(ver .: 0.5.1)却忽略了这一点。

Write Custom Encoder

遵循已接受的miracle2k答案并重复使用自定义json编码器。

答案 3 :(得分:2)

您是否只能使用dataclasses.asdict()函数来转换数据类 一个命令?像这样:

>>> @dataclass
... class Foo:
...     a: int
...     b: int
...     
>>> x = Foo(1,2)
>>> json.dumps(dataclasses.asdict(x))
'{"a": 1, "b": 2}'

答案 4 :(得分:2)

我建议使用 to_json() 方法为您的数据类创建一个父类:

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}'

如果您有其他功能要添加到所有数据类中,这将特别有用。

答案 5 :(得分:1)

使用字典解包on Reddit可以找到更简单的答案

>>> 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)

答案 6 :(得分:0)

好的,这是我在类似情况下所做的。

  1. 创建一个自定义字典工厂,将嵌套数据类转换为字典。

    定义我的工厂(数据): return dict(x for x in data if x[1] is not None)

  2. 如果 foo 是您的@dataclass,那么只需提供您的字典工厂以使用“myfactory()”方法:

    fooDict = asdict(foo, dict_factory=myfactory)

  3. 将 fooDict 转换为 json

    fooJson = json.dumps(fooDict)

这应该可行!!