JSON转储自定义格式

时间:2013-04-28 15:37:25

标签: python json dictionary

我想将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]

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

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

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

3 个答案:

答案 0 :(得分:5)

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

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继承。

答案 1 :(得分:2)

您需要创建json.JSONEncoder类的子类并覆盖这些方法 对于每种类型的值,它们都会编写您需要的格式。您最终可能会重新实施 大多数,取决于您的格式需求。

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

答案 2 :(得分:1)

我使用了蒂姆·卢德温斯基(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

另请参阅version I have in use