Json-сериализация вложенных классов данных

Мне нужно было бы задать вопрос о json serialization of @dataclass из Make Python json кодировщик поддерживает новые классы данных Python немного дальше: рассмотрите, когда они находятся во вложенной структуре.

Рассмотреть возможность:

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

Обратите внимание, что приведенное выше действительно включает один из ответов https://stackoverflow.com/a/59688140/1056563. Он утверждает, что поддерживает вложенный случай через декоратор dataclass_json. Видимо, это на самом деле не работает.

Я также попробовал другой ответ https://stackoverflow.com/a/51286749/1056563:

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)

Но использование этого метода также не повлияло на результат (ошибка). Любые дополнительные советы?


person WestCoastProjects    schedule 02.04.2020    source источник


Ответы (3)


Вы можете использовать библиотеку pydantic. Из примера в документации

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}
person Nikita Vostrosablin    schedule 16.04.2021
comment
Это то, что я искал. спасибо - person WestCoastProjects; 16.04.2021

На самом деле это не прямой ответ, а скорее разумный обходной путь для случаев, когда изменчивость не требуется (или желательна). NamedTuple на основе typing выглядит и ощущается очень похоже и, вероятно, является источником вдохновения для dataclass. Если бы сериализация была необходима, это, вероятно, в настоящее время лучшая альтернатива.

from typing import NamedTuple

class Prod(NamedTuple):
    id: str
    name: str
    price: str

Я сделал это как замену классу Prod на основе dataclass, и это работает.

person WestCoastProjects    schedule 02.04.2020

person    schedule
comment
Сериализация происходит на dict, а не на самом @dataclass. Подумайте о де-сериализации: затем нужно понять, чтобы вернуть словарь в класс данных. - person WestCoastProjects; 03.05.2020
comment
Посмотрите на это: github.com/EvgeniyBurdin/validated_dc Может поможет :) - person Evgeniy_Burdin; 03.05.2020
comment
Это хорошая ссылка! - person WestCoastProjects; 04.05.2020