【问题标题】:JSON encoding for dict of dictsdicts 的 JSON 编码
【发布时间】:2014-02-20 11:01:26
【问题描述】:

假设我有一个由原始字典组成的自定义数据结构。我需要使用 JSON 序列化它。我的结构如下:

path_list_dict = {(node1, node2 .. nodeN): (float1, float2, float3)}

所以这是一个元组键,值是三个值的元组。 键中的每个节点元素都是一个自定义类对象,并为其编写了 _str_ 方法。用一个键标识 path_list_dict 中每个 dict 条目的包装 dict 如下:

path_options_dict = {‘Path1’: {(node1, node2 .. nodeN): (float1, float2, float3)}, ‘Path2’: {(nodeA1, nodeA2 .. nodeAN): (floatA1, floatA2, floatA3)} }

等等。

当我尝试使用 JSON 对其进行序列化时,当然会遇到 TypeError,因为内部 dict 将元组作为键和值,而 dict 需要将键作为要序列化的字符串。这可以通过将作为 str(tuple) 表示形式插入到 dict 中而不只是本地元组来轻松解决。

我担心的是,当我收到它并解包值时,我将在接收端拥有所有字符串。由自定义类元素组成的内部 dict 的键元组现在表示为 str。我能恢复嵌入的数据吗?还是这些其他方法可以更好地做到这一点?

为了更清楚,我使用这个JSON tutorial 作为参考。

【问题讨论】:

    标签: python json serialization python-3.x


    【解决方案1】:

    您有多种选择:

    • 使用您可以选择并再次反序列化的自定义键前缀进行序列化:

      tuple_key = '__tuple__({})'.format(','.join(key))
      

      将产生'__tuple__(node1,node2,nodeN)' 作为键,您可以将其解析回另一端的元组:

      if key.startswith('__tuple__('):
           key = tuple(key[10:-1].split(','))
      

      演示:

      >>> key = ('node1', 'node2', 'node3')
      >>> '__tuple__({})'.format(','.join(key))
      '__tuple__(node1,node2,node3)'
      >>> mapped_key = '__tuple__({})'.format(','.join(key))
      >>> tuple(mapped_key[10:-1].split(','))
      ('node1', 'node2', 'node3')
      
    • 不要使用字典,使用列表列表:

      {'Path': [[[node1, node2 .. nodeN], [float1, float2, float3]], [...]]}
      

      您可以简单地从dict.items() 结果构建这样一个列表:

      >>> json.dumps({(1, 2, 3): ('foo', 'bar')}.items())
      '[[[1, 2, 3], ["foo", "bar"]]]'
      

      解码时,将整个内容反馈到dict(),同时将每个键值列表映射到元组:

      >>> dict(map(tuple, kv) for kv in json.loads('[[[1, 2, 3], ["foo", "bar"]]]'))
      {(1, 2, 3): (u'foo', u'bar')}
      

    后一种方法也更适合自定义类,因为 JSONEncoder.default() method 仍将被传递给这些自定义对象,以便您序列化回合适的字典对象,这意味着将合适的 object_hook 传递给 @ 987654322@ 有机会再次为这些对象返回完全反序列化的自定义对象。

    【讨论】:

    • 感谢您的帮助。我使用 dicts 的第二种方法是因为路径是唯一的,我需要这些键来检索它们以进行某些处理。第一个字典用于内部路径查找,并且这些字典中的键是唯一的。我需要在另一个模块中选择其中一个路径,并且必须确定选择哪个路径在内部进行更多后期处理,这就是我使用包装器的原因。第二种方法无法帮助我确定选择了哪条路径。因此这个。另外,您能否详细说明第一种方法?
    • 请原谅我的天真。我在您的所有示例中都看到,您的元组由字符串组成。我知道这只是为了说明方法,但是自定义类在将它们转换为字符串后会保留它们的反序列化属性吗?显然,如果解决了这个问题,这两种方法对我来说都非常有效。再次感谢您的清晰解释。
    • @adwaraki:如果你的元组包含字符串而是自定义对象,你需要找到一些其他的方法来序列化和反序列化它们。这确实超出了这个答案的范围。
    • 我很抱歉。我应该对问题本身更清楚。我添加了这句话,但为了清楚起见,应该大胆面对它。有什么地方可以带我去吗?
    • @adwaraki: 你可以给你的自定义类一个 __json__ 方法来将它们转换成一个可以被 json 序列化的值,以及一个类方法来再次从 JSON 中恢复对象,但是存储元组中的那些变得更加复杂。
    猜你喜欢
    • 2019-08-28
    • 2013-03-05
    • 2018-04-30
    • 2017-05-17
    • 2018-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-08
    相关资源
    最近更新 更多