使用JSON将JSON字符串反序列化为嵌套对象

时间:2019-04-22 16:07:52

标签: json python-3.x object python-dataclasses

我正在尝试使用jsons将json字符串反序列化为对象,但是嵌套对象有问题,但是无法计算语法。

作为示例,以下代码尝试将数据结构定义为一系列数据类,但未能反序列化嵌套对象C和D?语法显然是错误的,但对我来说尚不清楚应如何构造

http://torrent.ubuntu.com:6969/announce

谁能指出从json反序列化对象的正确方法?

4 个答案:

答案 0 :(得分:1)

您的尝试有两个相对简单的问题:

  1. 您忘了用C装饰@dataclass
  2. Test.CTest.D不是用类型定义的,而是用这些类型的 instances 定义的。 (此外,您希望两个字段都是给定类型的列表,而不是每个字段的单个实例。)

给出代码

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

答案 1 :(得分:0)

您可以执行以下操作:

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

答案 2 :(得分:0)

我终于设法通过删除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定义来构造原始帖子,将不胜感激。

答案 3 :(得分:0)

from dataclasses import dataclass
from typing import List

from validated_dc import ValidatedDC


@dataclass
class D(ValidatedDC):
    E: str


@dataclass
class C(ValidatedDC):
    id: int
    name: str


@dataclass
class Test(ValidatedDC):
    A: str
    B: int
    C: List[C]
    D: List[D]


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

instance = Test(**jsonString)

assert instance.C == [C(id=1, name='one'), C(id=2, name='two')]
assert instance.C[0].id == 1
assert instance.C[1].name == 'two'

assert instance.D == [D(E='e')]
assert instance.D[0].E == 'e'

ValidatedDC:https://github.com/EvgeniyBurdin/validated_dc