【问题标题】:Why is python's json.loads/dumps roundtrip lossy?为什么 python 的 json.loads/dumps 往返有损?
【发布时间】:2017-06-12 19:15:06
【问题描述】:

我正在使用 python 序列化一个 python 对象以将其存储在我的缓存中。对于这个序列化,我使用json.dumps() 并在将其从缓存中取出后对其进行反序列化,我使用json.loads()。我认为这次往返不会有任何麻烦。但正如您在下面看到的那样,它失败了。

>>> import json
>>> from collections import namedtuple
>>> x = {"hello": 1, "goodbye": 2}
>>> y = namedtuple('Struct', x.keys())(*x.values())
>>> y
Struct(goodbye=2, hello=1)

>>> json.loads(json.dumps(y))
[2, 1]           # <= I expected this to be the same value as y above!!

为什么这个 json.dumps/loads 往返有损?我可以使用什么函数将此对象序列化为反序列化将保留其原始值?我尝试使用pickle,但无法序列化对象。

【问题讨论】:

  • json 不知道命名元组。
  • JSON 并不意味着处理任意用户定义的对象类型。 JSON 支持对应于 Python dict 的“json 对象”和对应于 Python list 的“JSON 数组”。显然,python json 模块假定如果您将其传递给 tuple,它将被序列化为 JSON 数组。但这将始终被反序列化为 Python 列表。您可以使用pickle 序列化namedtuple 返回的类型,但您必须保留该类型。您创建类型、实例化类型并一举丢弃类型:namedtuple('Struct', x.keys())(*x.values()).
  • @juanpa.arrivillaga 为什么不从这么长的评论中做出回答?
  • @Jean-FrançoisFabre 所以,我很确定这是某个地方的副本,我一直在寻找它,但仍然没有找到。我可能记错了。我认为你的答案很好,我会取消删除它。
  • @juanpa.arrivillaga 我找到了一个类似的问答,但它不是重复的,因为它没有解释字段名称丢失的原因。

标签: python json serialization


【解决方案1】:

json 尝试根据对象的类型序列化对象。它不能序列化任何对象,只能序列化“基本”对象,例如tuple(转换为方括号,如list)、dictlist ...(当然还有整数、字符串、浮点数)。

当使用isinstance 测试您的对象时,它会在tuple 上成功,因为namedtuple 被设计为继承自tuple

y = namedtuple('Struct', x.keys())(*x.values())
print(isinstance(y,tuple))

结果是True

所以在json 模块的encoder.py 文件中,您的数据与iterencode 方法中的isinstance 测试相匹配(下面的代码摘录,我的Python 3.4 版本的第311 行左右):

   if isinstance(value, (list, tuple)):
        chunks = _iterencode_list(value, _current_indent_level)

所以从listtuple 继承的任何类型都像list 一样被序列化

这里提出了一个解决方法:Serializing a Python namedtuple to json

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-19
    • 1970-01-01
    • 2017-02-04
    相关资源
    最近更新 更多