I\'d like to dump a Python dictionary into a JSON file with a particular custom format. For example, the following dictionary my_dict
,
\'text_li
You will need to create a subclass of the json.JSONEncoder class and override the methods for each type of value so they write the format you need. You may end up re-implementing most of them, depending on what your formatting needs are.
http://docs.python.org/2/library/json.html has an example for extending the JSONEncoder.
Here's something that I hacked together. Not very pretty but it seems to work. You could probably handle simple dictionaries in a similar way.
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)
NOTE: It's pretty much unnecessary in this code to be inheriting from JSONEncoder
.
I have used the example provided by Tim Ludwinski and adapted it to my preference:
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
Also see the version I have in use.