Десериализовать строку JSON во вложенные объекты с помощью jsons - PullRequest
0 голосов
/ 22 апреля 2019

Я пытаюсь десериализовать строку json в объект, используя jsons , но у меня проблемы с вложенными объектами, но не удается разобрать синтаксис.

В качестве примера приведен следующий кодпытается определить структуру данных как серию классов данных, но не может десериализовать вложенные объекты C и D?Синтаксис явно неправильный, но мне не ясно, как он должен структурироваться

import jsons
from dataclasses import dataclass

@dataclass
class D:
    E: str
class C:
    id: int
    name:str
@dataclass
class test:
    A: str
    B: int
    C: C()
    D: D()

jsonString = {"A":"a","B":1,"C":[{"id":1,"name":"one"},{"id":2,"name":"two"}],"D":[{"E":"e"}]}
instance = jsons.load(jsonString, test)

Может кто-нибудь указать правильный способ десериализации объектов из json?

Ответы [ 3 ]

1 голос
/ 22 апреля 2019

Есть две относительно простые проблемы с вашей попыткой:

  1. Вы забыли украсить C с помощью @dataclass.
  2. Test.C и Test.D нетопределяется с типами, но с экземплярами типов.(Кроме того, вы хотите, чтобы оба поля были списками данного типа, а не отдельными экземплярами каждого.)

С учетом кода

import jsons
from dataclasses import dataclass
from typing import List


@dataclass
class D:
    E: str


@dataclass  # Problem 1 fixed
class C:
    id: int
    name: str


@dataclass
class Test:
    A: str
    B: int
    C: List[C]  # Problem 2 fixed; List[C] not C() or even C
    D: List[D]  # Problem 2 fixed; List[D], not D() or even D

Тогда

>>> obj = {"A":"a", "B":1, "C": [{"id": 1,"name": "one"}, {"id": 2, "name": "two"}], "D":[{"E": "e"}]}
>>> jsons.load(obj, Test)
test(A='a', B=1, C=[C(id=1, name='one'), C(id=2, name='two')], D=[D(E='e')])
0 голосов
/ 22 апреля 2019

Мне, наконец, удалось заставить это работать, удалив определение dataClass и расширив определения классов старой школы .... код следующим образом ...

import jsons

class D:
     def __init__(self, E = ""):
         self.E = E
class C:
    def __init__(self, id = 0, name=""):
        self.id = id
        self.name = name
class test:
    def __init__(self, A = "", B = 0, C = C(), D = D()):
        self.A = A
        self.B = B
        self.C = C
        self.D = D

jsonString = {"A":"a","B":1,"C":[{"id":1,"name":"one"},{"id":2,"name":"two"}],"D":[{"E":"e"}]}
instance = jsons.load(jsonString, test)

Теперь это работает, ноне так чист, как с dataClass.Благодарен, если кто-нибудь может указать, как оригинальный пост может быть построен с определением dataClass.

0 голосов
/ 22 апреля 2019

Вы можете сделать что-то вроде этого:

from collections import namedtuple
# First parameter is the class/tuple name, second parameter
# is a space delimited string of varaibles.
# Note that the variable names should match the keys from 
# your dictionary of arguments unless only one argument is given.
A = namedtuple("A", "a_val") # Here the argument `a_val` can be called something else
B = namedtuple("B", "num")
C = namedtuple("C", "id name")
D = namedtuple("D", "E") # This must be `E` since E is the key in the dictionary.
# If you dont want immutable objects to can use full classes
# instead of namedtuples

# A dictionary which matches the name of an object seen in a payload
# to the object we want to create for that name.
object_options = {
  "A": A,
  "B": B,
  "C": C,
  "D": D
}
my_objects = [] # This is the list of object we get from the payload

jsonString = {"A":"a","B":1,"C":[{"id":1,"name":"one"},{"id":2,"name":"two"}],"D":[{"E":"e"}]}

for key, val in jsonString.items():
    if key in object_options: # If this is a valid object
        if isinstance(val, list): # If it is a list of this object
            for v in val: # Then we need to add each object in the list
                my_objects.append(object_options[key](**v))
        elif isinstance(val, dict): # If the object requires a dict then pass the whole dict as arugments
            my_objects.append(object_options[key](**val))
        else: # Else just add this object with a singular argument.
            my_objects.append(object_options[key](val))
print(my_objects)

Вывод:

[A(a_val='a'), B(num=1), C(id=1, name='one'), C(id=2, name='two'), D(E='e')]
...