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

使Python json编码器支持Python';新的数据类,python,python-dataclasses,Python,Python Dataclasses,从Python 3.7开始,有一种称为dataclass的东西: 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 serializa

从Python 3.7开始,有一种称为dataclass的东西:

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()
Foo
的实例编码为json?

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

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)

您不能只使用
dataclasses.asdict()
函数来转换数据类吗 口述?比如:

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

如果您同意使用库进行此操作,则可以使用。以下是一个例子:

从数据类导入数据类
从dataclass_json导入dataclass_json
@dataclass_json
@数据类
Foo类:
x:str
foo=foo(x=“一些字符串”)
foo_json=foo.to_json()
它还支持嵌入式数据类——如果您的数据类有一个作为另一个数据类键入的字段——如果所有已解决的数据类都有
@dataclass\u json
装饰器

获取JSONified dataclass实例的方法 实现该目标有两种选择,每种选择都意味着分析哪种方法最适合您的需要:

将其提取回dataclass实例并不简单,所以您可能希望访问该答案

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

此外,请注意,marshmallow数据类为您进行了类型转换,而dataclassses json(版本:0.5.1)忽略了这一点


遵循公认的2K答案并重用自定义json编码器。

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

>>从数据类导入数据类
>>>@dataclass
... 类别MyData:
...   prop1:int
...   prop2:str
...   prop3:int
...
>>>d={'prop1':5'prop2':'hi','prop3':100}
>>>我的数据=我的数据(**d)
>>>我的数据
MyData(prop1=5,prop2='hi',prop3=100)

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

导入json
从数据类导入数据类,asdict
@数据类
类别数据类别:
def to_json(self)->str:
返回json.dumps(asdict(self))
@数据类
类YourDataclass(数据类):
a:整数
b:int
x=YourDataclass(a=1,b=2)
x、 to_json()#“{”a:1,“b:2}”

如果要向所有数据类添加其他功能,这一点尤其有用。

数据类可能是大型结构的深层嵌套部分。通过使用自定义编码器,您可以执行
json.dumps({“obj”:[某些东西可能包含或不包含数据类])
asasdict()将正确处理所有嵌套的数据类,因此,我们得到通常加载到jison字符串中的嵌套字典(但是!例如,在加载到字符串中之前,必须另外处理datetime类型)需要注意的是,对于名为
Foo
的数据类和一个实例
Foo\u instance=Foo(…)
这两个
dataclasses.is\u dataclass(Foo)
dataclasses.is\u dataclass(Foo\u instance)
计算为
True
会导致
dataclasses.asdict(o)的
TypeError
if
o
ist是数据类本身,而不是它的一个实例。嵌套如何-例如序列化
d={'a':Foo(1,2),'b':Foo(3,4)}
如何处理ndarray类型的对象?我用嵌入式数据类尝试了这个方法,但它不起作用谢谢
marshmallow_数据类
这确实是一个很好的方法,可以通过验证(甚至YAML)从JSON获取真正的对象。@mickours欢迎:)顺便说一句,我没有提到它也可以在python36上工作(在引擎盖下有dataclass backport)这不支持嵌套的dataclass。如果d来自json对象,这可能会引入错误。我们通常认为在有效负载中添加字段不是一个突破性的更改,但在这里,如果您向d添加字段,它将以“获得意外的关键字参数‘prop4’”而中断
import dataclasses
import json


@dataclass.dataclass
class Foo:
    x: str

foo = Foo(x='1')
json_foo = json.dumps(dataclasses.asdict(foo)) # '{"x": "1"}'
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)
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')