Python JSON转储自定义格式

Python JSON转储自定义格式,python,json,dictionary,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": [

我想将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]
而我更喜欢它看起来像这样

  "text_lines": [
    {
      "line1"
    }, 
    {
      "line2"
    }
  ]
  "text_lines": 
  [
    {"line1"}, 
    {"line2"}
  ]
  "location": [22, -8]
同样,我想要以下内容

  "location": [
    22, 
    -8
  ]
像这样

  "text_lines": [
    {
      "line1"
    }, 
    {
      "line2"
    }
  ]
  "text_lines": 
  [
    {"line1"}, 
    {"line2"}
  ]
  "location": [22, -8]
(也就是说,更像一个坐标,它是)

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


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

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

有一个扩展的例子
JSONECODER。

这是我拼凑的东西。不是很漂亮,但似乎很管用。您可能可以用类似的方式处理简单的词典

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)

注意:在这段代码中,从
jsonecoder
继承几乎是不必要的

我使用了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
class CompactJSONEncoder(json.JSONEncoder):
“”“将小列表放在单行上的JSON编码器。”“”
定义初始化(self,*args,**kwargs):
super()
self.u级别=0
def编码(自身,o):
“”“针对单行列表对JSON对象*o*进行编码。”“”
如果isinstance(o,(列表,元组)):
如果self.\u是单行列表(o):
返回“[”+“,”.join(o中el的json.dumps(el)+”]”
其他:
self.u级别+=1
输出=[self.indent_str+self.encode(el)表示el在o中]
self.u level-=1
返回“[\n”+”,\n.join(output)+“\n”+self.indent\u str+”]
elif isinstance(o,dict):
self.u级别+=1
output=[self.indent_str+f“{json.dumps(k)}:{self.encode(v)}”表示k,v在o.items()中]
self.u level-=1
返回“{\n”+”,\n.join(output)+“\n”+self.indent\u str+”}”
其他:
返回json.dumps(o)
定义是单行列表(self,o):
如果isinstance(o,(列表,元组)):
对于o中的el,不返回任何(isinstance(el,(list,tuple,dict))值)\

顺便说一句,len(o)不是一个有效的JSON。。。它是否真的起作用了?不是为了说明问题,但你的json指令仍然无效。(即每个dict都需要一个键和值:{“line1”:“value1})。你知道吗?我不知道如何使用JSONEncoder来实现这一点。举个例子就好了。不知道如何使用JSONEncoder来实现这一点。请注意,你可以用
替换
”。join([“”表示范围内的x(self.current\u indent)])
“*自身当前缩进
;-)如果有人想知道:这对于打印GeoJSON非常有效。我非常喜欢你的解决方案,尤其是要点中的解决方案,谢谢。