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

Mav*_*ckD 3 python json python-3.x

我有一个这种格式的字符串,

d = {'details': {'hawk_branch': {'tandem': ['4210bnd72']}, 'uclif_branch': {'tandem': ['e2nc712nma89', '23s24212', '12338cm82']}}}
Run Code Online (Sandbox Code Playgroud)

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

  "tandem": {
    "value": "4210bnd72"
  }
Run Code Online (Sandbox Code Playgroud)

这是预期的输出文件,

{
  "details": {

    "hawk_branch": {
      "tandem": {
        "value": "4210bnd72"
      }
    },
    "uclif_branch": {
      "tandem": {
        "value": "e2nc712nma89",
        "value": "23s24212",
        "value": "12338cm82",
      }
    }
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里问了一个问题,有人回答使用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)
Run Code Online (Sandbox Code Playgroud)

使用上面的编码器,如果输入是,

d = {'details': {'hawk_branch': {'tandem': ['4210bnd72']}, 'uclif_branch': {'tandem': ['e2nc712nma89', '23s24212', '12338cm82']}}}
Run Code Online (Sandbox Code Playgroud)

输出将变成,

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

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

with open("a.json", "w") as f:
    json.dump(d, f, cls=restore_value)
Run Code Online (Sandbox Code Playgroud)

但它的写入方式与json.dumps.

预期输出,

{"details": {"hawk_branch": {"tandem": {"value": "4210bnd72"}}, "uclif_branch": {"tandem": {"value": "e2nc712nma89", "value": "23s24212", "value": "12338cm82"}}}}
Run Code Online (Sandbox Code Playgroud)

我得到的输出,

{"details": {"hawk_branch": {"tandem": ["4210bnd72"]}, "uclif_branch": {"tandem": ["e2nc712nma89", "23s24212", "12338cm82"]}}}
Run Code Online (Sandbox Code Playgroud)

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

繁殖,

使用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)
Run Code Online (Sandbox Code Playgroud)

Roc*_* Li 6

原因在这里:

如果你看看源代码,json.__init__.pyCPython/Lib/json这里github上:https://github.com/python/cpython/blob/master/Lib/json/初始化的.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)
Run Code Online (Sandbox Code Playgroud)

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