Json 嵌套数据类的序列化
Json serialization of nested dataclasses
我需要进一步回答 中关于 json serialization of @dataclass
的问题:考虑它们何时处于嵌套结构中。
考虑:
import json
from attr import dataclass
from dataclasses_json import dataclass_json
@dataclass
@dataclass_json
class Prod:
id: int
name: str
price: float
prods = [Prod(1,'A',25.3),Prod(2,'B',79.95)]
pjson = json.dumps(prods)
这给了我们:
TypeError: Object of type Prod is not JSON serializable
请注意,上面确实包含了答案之一 。它声称通过 dataclass_json
装饰器支持嵌套大小写。显然这实际上不起作用。
我也尝试了另一个答案 :
class EnhancedJSONEncoder(json.JSONEncoder):
def default(s, o):
if dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
return super().default(o)
我为它创建了一个辅助方法:
def jdump(s,foo):
return json.dumps(foo, cls=s.c.EnhancedJSONEncoder)
但是使用该方法也没有影响(错误)结果。还有其他提示吗?
这实际上不是直接的答案,而是对于不需要(或不希望)可变性的情况的更合理的解决方法。基于 typing
的 NamedTuple
看起来和感觉起来非常相似,可能是 dataclass
背后的灵感来源。如果需要序列化,它可能是目前最好的选择。
from typing import NamedTuple
class Prod(NamedTuple):
id: str
name: str
price: str
我将其作为基于 dataclass
的 Prod
class 的直接替代品并且它有效。
import json
from dataclasses import dataclass, asdict
@dataclass
class Prod:
id: int
name: str
price: float
prods = [asdict(Prod(1, 'A', 25.3)), asdict(Prod(2, 'B', 79.95))]
pjson = json.dumps(prods)
print(pjson)
# [{"id": 1, "name": "A", "price": 25.3}, {"id": 2, "name": "B", "price": 79.95}]
您可以使用 pydantic
库。来自 documentation
中的示例
from pydantic import BaseModel
class BarModel(BaseModel):
whatever: int
class FooBarModel(BaseModel):
banana: float
foo: str
bar: BarModel
m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123})
# returns a dictionary:
print(m.dict())
"""
{
'banana': 3.14,
'foo': 'hello',
'bar': {'whatever': 123},
}
"""
print(m.dict(include={'foo', 'bar'}))
#> {'foo': 'hello', 'bar': {'whatever': 123}}
print(m.dict(exclude={'foo', 'bar'}))
#> {'banana': 3.14}
我需要进一步回答 json serialization of @dataclass
的问题:考虑它们何时处于嵌套结构中。
考虑:
import json
from attr import dataclass
from dataclasses_json import dataclass_json
@dataclass
@dataclass_json
class Prod:
id: int
name: str
price: float
prods = [Prod(1,'A',25.3),Prod(2,'B',79.95)]
pjson = json.dumps(prods)
这给了我们:
TypeError: Object of type Prod is not JSON serializable
请注意,上面确实包含了答案之一 dataclass_json
装饰器支持嵌套大小写。显然这实际上不起作用。
我也尝试了另一个答案
class EnhancedJSONEncoder(json.JSONEncoder):
def default(s, o):
if dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
return super().default(o)
我为它创建了一个辅助方法:
def jdump(s,foo):
return json.dumps(foo, cls=s.c.EnhancedJSONEncoder)
但是使用该方法也没有影响(错误)结果。还有其他提示吗?
这实际上不是直接的答案,而是对于不需要(或不希望)可变性的情况的更合理的解决方法。基于 typing
的 NamedTuple
看起来和感觉起来非常相似,可能是 dataclass
背后的灵感来源。如果需要序列化,它可能是目前最好的选择。
from typing import NamedTuple
class Prod(NamedTuple):
id: str
name: str
price: str
我将其作为基于 dataclass
的 Prod
class 的直接替代品并且它有效。
import json
from dataclasses import dataclass, asdict
@dataclass
class Prod:
id: int
name: str
price: float
prods = [asdict(Prod(1, 'A', 25.3)), asdict(Prod(2, 'B', 79.95))]
pjson = json.dumps(prods)
print(pjson)
# [{"id": 1, "name": "A", "price": 25.3}, {"id": 2, "name": "B", "price": 79.95}]
您可以使用 pydantic
库。来自 documentation
from pydantic import BaseModel
class BarModel(BaseModel):
whatever: int
class FooBarModel(BaseModel):
banana: float
foo: str
bar: BarModel
m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123})
# returns a dictionary:
print(m.dict())
"""
{
'banana': 3.14,
'foo': 'hello',
'bar': {'whatever': 123},
}
"""
print(m.dict(include={'foo', 'bar'}))
#> {'foo': 'hello', 'bar': {'whatever': 123}}
print(m.dict(exclude={'foo', 'bar'}))
#> {'banana': 3.14}