json编码器json.dump和json.dumps的结果不同

时间:2018-10-22 23:49:29

标签: python json python-3.x

我有这种格式的字符串,

d = {'details': {'hawk_branch': {'tandem': ['4210bnd72']}, 'uclif_branch': {'tandem': ['e2nc712nma89', '23s24212', '12338cm82']}}}

我想以这种格式将其写入文件,将列表转换为字典,并为列表中的每个值添加单词value作为键, 因此{'tandem': ['4210bnd72']}应该变成

  "tandem": {
    "value": "4210bnd72"
  }

这是预期的输出文件,

{
  "details": {

    "hawk_branch": {
      "tandem": {
        "value": "4210bnd72"
      }
    },
    "uclif_branch": {
      "tandem": {
        "value": "e2nc712nma89",
        "value": "23s24212",
        "value": "12338cm82",
      }
    }
    }
}

我问了一个问题here,有人回答使用json.JSONEncoder

class restore_value(json.JSONEncoder):
    def encode(self, o):
        if isinstance(o, dict):
            return '{%s}' % ', '.join(': '.join((json.encoder.py_encode_basestring(k), self.encode(v))) for k, v in o.items())
        if isinstance(o, list):
            return '{%s}' % ', '.join('"value": %s' % self.encode(v) for v in o)
        return super().encode(o)

使用上述编码器,如果输入为

d = {'details': {'hawk_branch': {'tandem': ['4210bnd72']}, 'uclif_branch': {'tandem': ['e2nc712nma89', '23s24212', '12338cm82']}}}

输出将变为

print(json.dumps(d, cls=restore_value))
{"details": {"hawk_branch": {"tandem": {"value": "4210bnd72"}}, "uclif_branch": {"tandem": {"value": "e2nc712nma89", "value": "23s24212", "value": "12338cm82"}}}}

这正是我想要的,但是现在我想将其写入文件。

with open("a.json", "w") as f:
    json.dump(d, f, cls=restore_value)

但是它的写入方式与json.dumps的输出方式不同。

预期输出

{"details": {"hawk_branch": {"tandem": {"value": "4210bnd72"}}, "uclif_branch": {"tandem": {"value": "e2nc712nma89", "value": "23s24212", "value": "12338cm82"}}}}

我得到的输出

{"details": {"hawk_branch": {"tandem": ["4210bnd72"]}, "uclif_branch": {"tandem": ["e2nc712nma89", "23s24212", "12338cm82"]}}}

有人可以告诉我,即使我使用编码器,为什么写入文件的方式也不同?

复制

使用python 3复制并运行它,

import json


class restore_value(json.JSONEncoder):
    def encode(self, o):
        if isinstance(o, dict):
            return '{%s}' % ', '.join(': '.join((json.encoder.py_encode_basestring(k), self.encode(v))) for k, v in o.items())
        if isinstance(o, list):
            return '{%s}' % ', '.join('"value": %s' % self.encode(v) for v in o)
        return super().encode(o)

d = {'details': {'hawk_branch': {'tandem': ['4210bnd72']}, 'uclif_branch': {'tandem': ['e2nc712nma89', '23s24212', '12338cm82']}}}
print(json.dumps(d, cls=restore_value))


with open("a.json", "w") as f:
  json.dump(d, f, cls=restore_value)

2 个答案:

答案 0 :(得分:3)

原因在这里:

如果您在github上的json.__init__.py中查看CPython/Lib/json的源代码:https://github.com/python/cpython/blob/master/Lib/json/init.py

您会发现json.dump实际使用:

if (not skipkeys and ensure_ascii and
    check_circular and allow_nan and
    cls is None and indent is None and separators is None and
    default is None and not sort_keys and not kw):
    iterable = _default_encoder.iterencode(obj)
else:
    if cls is None:
        cls = JSONEncoder
    iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,
        check_circular=check_circular, allow_nan=allow_nan, indent=indent,
        separators=separators,
        default=default, sort_keys=sort_keys, **kw).iterencode(obj)
# could accelerate with writelines in some versions of Python, at
# a debuggability cost
for chunk in iterable:
    fp.write(chunk)

因此,您想override使用的功能应该是json.JSONEncoder.iterencode而不是encode

答案 1 :(得分:1)

带有json.dumps

cls将在您的JSON对象上调用encode方法,该方法将返回字符串表示形式。另一方面,json.dump将调用您尚未实现的default方法。来自json.dump文档:

  

要使用自定义JSONEncoder子类(例如,一个覆盖default()方法以序列化其他类型的子类),请使用cls kwarg指定它;否则将使用JSONEncoder。

因此,json.dump使用默认的default方法,该方法不会影响您的原始对象并将其写入。

以所需方式写入文件的最简单方法是

with open("a.json", "w") as f:
    f.write(json.dumps(d, cls=restore_value))