我想将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]
(也就是说,更像是一个坐标)。
我知道这是一个美容问题,但对我来说保留这种格式以便于手动编辑文件非常重要。
任何方式进行这种定制?一个解释的例子会很棒(文档并没有让我走得太远)。
答案 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