【问题标题】:Converting Nested Json into Python object将嵌套的 Json 转换为 Python 对象
【发布时间】:2017-10-02 05:45:45
【问题描述】:

我有如下嵌套的json

{
"product" : "name",
"protocol" : "scp",
"read_logs" : {
    "log_type" : "failure",
    "log_url" : "htttp:url"
    }
}

我正在尝试使用以下代码创建 Python 类对象。

import json
class Config (object):
    """
    Argument: JSON Object from the configuration file.
    """
   def __init__(self, attrs):
        if 'log_type' in attrs:
            self.log_type = attrs['log_type']
            self.log_url = attrs['log_url']
        else:
           self.product = attrs["product"]
           self.protocol = attrs["protocol"]
   def __str__(self):
       return "%s;%s" %(self.product, self.log_type)

   def get_product(self):
        return self.product

   def get_logurl(self):
       return self.log_url

class ConfigLoader (object):
    '''
        Create a confiuration loaded which can read JSON config files
    '''
    def load_config (self, attrs):
        with open (attrs) as data_file:
            config = json.load(data_file, object_hook=load_json)
        return config

def load_json (json_object):
    return Config (json_object)

loader = ConfigLoader()
config = loader.load_config('../config/product_config.json')

print config.get_protocol()

但是,object_hook 递归调用 load_json 并且 Class Config init 被调用了两次。所以我创建的最终对象不包含嵌套的 JSON 数据。

有没有办法将整个嵌套的 JSON 对象读入单个 Python 类?

谢谢

【问题讨论】:

    标签: python json


    【解决方案1】:

    Pankaj Singhal 想法的变体,但使用“通用”命名空间类而不是命名元组:

    import json
    
    class Generic:
        @classmethod
        def from_dict(cls, dict):
            obj = cls()
            obj.__dict__.update(dict)
            return obj
    
    data = '{"product": "name", "read_logs": {"log_type": "failure", "log_url": "123"}}'
    
    x = json.loads(data, object_hook=Generic.from_dict)
    print(x.product, x.read_logs.log_type, x.read_logs.log_url)
    

    【讨论】:

      【解决方案2】:

      namedtuple & object_hook 可以帮助创建单线:

      # Create an object with attributes corresponding to JSON keys.
      def json_to_obj(data): return json.loads(data, object_hook=lambda converted_dict: namedtuple('X', converted_dict.keys())(*converted_dict.values()))
      

      或者创建一个更易读的函数,如下所示:

      def _object_hook(converted_dict): return namedtuple('X', converted_dict.keys())(*converted_dict.values())
      def json_to_obj(data): return json.loads(data, object_hook=_object_hook)
      

      下面是使用它的代码sn-p:

      import json
      from collections import namedtuple
      
      data = '{"product": "name", "read_logs": {"log_type": "failure", "log_url": htttp:url}}'
      
      x = json_to_obj(data)
      print x.product, x.read_logs.log_type, x.read_logs.log_url
      

      注意:查看namedtuplerename parameter

      【讨论】:

      • 使用命名元组并不是语义上最好的选择,更不用说创建新的namedtuples 由于类创建而相当慢。
      【解决方案3】:

      我编写了一个简单的 DFS 算法来完成这项工作。

      将嵌套项转换为平面字典。就我而言,我用破折号加入了 json 项的键。

      例如,嵌套项 { "a":[{"b": "c"}, {"d":"e"}] } 将被转换为 {'a-0-b': 'c ', 'a-1-d': 'e'}。

      def DFS(item, headItem, heads, values):
          if type(item) == type({}):
              for k in item.keys():
                  DFS(item[k], headItem + [k], heads, values)
          elif type(item) == type([]):
              for i in range(len(item)):
                  DFS(item[i], headItem + [str(i)], heads, values)
          else:
              headItemStr = '-'.join(headItem)
              heads.append(headItemStr)
              values.append(item)
          return
      
      
      def reduce(jsonItem):
          heads, values = [], []
          DFS(jsonItem, [], heads, values)
          return heads, values
      
      
      def json2dict(jsonItem):
          head, value = reduce(jsonItem)
          dictHeadValue = { head[i] : value[i] for i in range(len(head))}
          return dictHeadValue
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多