23

我想将 Python 字典转储到具有特定自定义格式的 JSON 文件中。例如,下面的字典my_dict

'text_lines': [{"line1"}, {"line2"}]

倾倒

f.write(json.dumps(my_dict, sort_keys=True, indent=2))

看起来像这样

  "text_lines": [
    {
      "line1"
    }, 
    {
      "line2"
    }
  ]

虽然我更喜欢它看起来像这样

  "text_lines": 
  [
    {"line1"}, 
    {"line2"}
  ]

同样,我想要以下

  "location": [
    22, 
    -8
  ]

看起来像这样

  "location": [22, -8]

(也就是说,它更像是一个坐标)。

我知道这是一个表面问题,但对我来说保留这种格式以便于手动编辑文件很重要。

有没有办法进行这种定制?一个解释的例子会很棒(文档并没有让我走得太远)。

4

3 回答 3

11

我使用了 Tim Ludwinski 提供的示例,并根据我的喜好对其进行了调整:

class CompactJSONEncoder(json.JSONEncoder):
    """A JSON Encoder that puts small lists on single lines."""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.indentation_level = 0

    def encode(self, o):
        """Encode JSON object *o* with respect to single line lists."""

        if isinstance(o, (list, tuple)):
            if self._is_single_line_list(o):
                return "[" + ", ".join(json.dumps(el) for el in o) + "]"
            else:
                self.indentation_level += 1
                output = [self.indent_str + self.encode(el) for el in o]
                self.indentation_level -= 1
                return "[\n" + ",\n".join(output) + "\n" + self.indent_str + "]"

        elif isinstance(o, dict):
            self.indentation_level += 1
            output = [self.indent_str + f"{json.dumps(k)}: {self.encode(v)}" for k, v in o.items()]
            self.indentation_level -= 1
            return "{\n" + ",\n".join(output) + "\n" + self.indent_str + "}"

        else:
            return json.dumps(o)

    def _is_single_line_list(self, o):
        if isinstance(o, (list, tuple)):
            return not any(isinstance(el, (list, tuple, dict)) for el in o)\
                   and len(o) <= 2\
                   and len(str(o)) - 2 <= 60

    @property
    def indent_str(self) -> str:
        return " " * self.indentation_level * self.indent
    
    def iterencode(self, o, **kwargs):
        """Required to also work with `json.dump`."""
        return self.encode(o)

另请参阅我使用的版本

于 2019-02-07T15:57:59.810 回答
8

这是我一起破解的东西。不是很漂亮,但它似乎工作。您可能可以以类似的方式处理简单的字典。

class MyJSONEncoder(json.JSONEncoder):
    def __init__(self, *args, **kwargs):
        super(MyJSONEncoder, self).__init__(*args, **kwargs)
        self.current_indent = 0
        self.current_indent_str = ""

    def encode(self, o):
        #Special Processing for lists
        if isinstance(o, (list, tuple)):
            primitives_only = True
            for item in o:
                if isinstance(item, (list, tuple, dict)):
                    primitives_only = False
                    break
            output = []
            if primitives_only:
                for item in o:
                    output.append(json.dumps(item))
                return "[ " + ", ".join(output) + " ]"
            else:
                self.current_indent += self.indent
                self.current_indent_str = "".join( [ " " for x in range(self.current_indent) ])
                for item in o:
                    output.append(self.current_indent_str + self.encode(item))
                self.current_indent -= self.indent
                self.current_indent_str = "".join( [ " " for x in range(self.current_indent) ])
                return "[\n" + ",\n".join(output) + "\n" + self.current_indent_str + "]"
        elif isinstance(o, dict):
            output = []
            self.current_indent += self.indent
            self.current_indent_str = "".join( [ " " for x in range(self.current_indent) ])
            for key, value in o.items():
                output.append(self.current_indent_str + json.dumps(key) + ": " + self.encode(value))
            self.current_indent -= self.indent
            self.current_indent_str = "".join( [ " " for x in range(self.current_indent) ])
            return "{\n" + ",\n".join(output) + "\n" + self.current_indent_str + "}"
        else:
            return json.dumps(o)

注意:在这段代码中几乎没有必要继承自JSONEncoder.

于 2014-10-22T16:07:55.667 回答
3

您将需要创建 json.JSONEncoder 类的子类并覆盖每种类型值的方法,以便它们编写您需要的格式。根据您的格式化需求,您最终可能会重新实现其中的大部分。

http://docs.python.org/2/library/json.html有一个扩展 JSONEncoder 的例子。

于 2013-04-28T16:00:45.507 回答