【问题标题】:JSON to class instance?JSON到类实例?
【发布时间】:2020-02-08 19:36:02
【问题描述】:

我有一个简单的类和 JSON:

@dataclass
class Point:
    x: int
    y: int

jsonString = '{"x": 3, "y": 5}'

我想将 JSON 数据转换为点的实例。 从 C# 很容易:

JsonConvert.DeserializeObject<Point>(jsonString);

如何在 Python 中做到这一点?

【问题讨论】:

  • DeserializeObject 会将对象中的 JSON 字符串转换为整数吗?
  • 如果您不需要将值从str 转换为int,您可以使用Point(**json.loads(jsonString))
  • Point 必须是dataclass 吗?
  • 到底是什么问题?那个字符串是从哪里来的?请参阅:How to Asktourhelp center。此外,变量和函数名称应遵循lower_case_with_underscores 样式。
  • 你要选择一个答案吗?

标签: python json deserialization


【解决方案1】:

我在其他地方进行 json 模式验证,所以简单的 like this 对我有用:

point = Point(**json.loads(jsonString))

【讨论】:

    【解决方案2】:

    您可以使用生成器表达式来使用适当的值, 通过解码字符串然后迭代对应于xy的值。

    >>> from operator import itemgetter
    >>> coords = itemgetter('x', 'y')
    >>> Point(*(int(x) for x in coords(json.loads(jsonString))))
    Point(x=3, y=5)
    

    coords 是一个函数,它返回一个由其参数的 xy 值组成的元组。生成器表达式确保每个值都转换为 int* 语法将生成器解包为单独的参数。

    不过,一个更惯用的解决方案是定义一个类方法来构造一个 Point 给定一个适当的对象:

    @dataclass
    class Point:
        x: int
        y: int
    
        @classmethod
        def from_dict(cls, d):
            return cls(d['x'], d['y'])
    
    p = Point.from_dict(json.loads(jsonString))
    

    您还可以定义一个from_json 类方法来包装from_dict

    @dataclass
    class Point:
        x: int
        y: int
    
        @classmethod
        def from_dict(cls, d):
            return cls(d['x'], d['y'])
    
        @classmethod
        def from_json(cls, j):
            return cls.from_dict(json.loads(j))
    
    p = Point.from_json(jsonString)
    

    虽然此处未显示,但类方法提供了对传递的 JSON 字符串或参数进行验证的位置,因此您可以更优雅地处理诸如缺少键、额外键、不是对象的 JSON 值等问题。

    【讨论】:

      【解决方案3】:

      这样的事情怎么样?

      编辑:如果 x 和 y 最初是字符串,您也可以将它们转换为整数:

      # define Point class:
      class Point():
      
          # define init function:
          def __init__(self, data):
              self.x = int(data['x'])
              self.y = int(data['y'])
      
      
      # your json point:
      json_data = {'x' : '2', 'y' : '3'}
      
      # convert to Point class:
      my_point = Point(json_data)
      
      print(my_point)
      print(my_point.x)
      print(my_point.y)        
      

      【讨论】:

        【解决方案4】:

        如果“简单类”实现为dataclass,如您的问题所示,可以使用如下所示的通用deserialize_dataclass 函数反序列化JSON 数据。

        dataclasses 使得内省修饰类变得相当容易,并且可以使用该信息提取和转换由字符串表示的 JSON 对象。

        import dataclasses
        import json
        dataclass = dataclasses.dataclass
        
        def deserialize_dataclass(DataClass, json_string):
            """ Convert the JSON object represented by the string into the dataclass
                specified.
            """
            json_obj = json.loads(json_string)
            dc_data = {field.name: field.type(json_obj[field.name])
                            for field in dataclasses.fields(DataClass)}
            return DataClass(**dc_data)
        
        @dataclass
        class Point:
            x: int
            y: int
        
        
        json_string = '{"x": "3", "y": "5"}'
        pt = deserialize_dataclass(Point, json_string)
        print(pt)  # -> Point(x=3, y=5)
        

        【讨论】:

          猜你喜欢
          • 2015-06-27
          • 1970-01-01
          • 2012-04-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多