JSON dumps custom formatting

后端 未结 3 1671
情深已故
情深已故 2020-12-03 16:56

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         


        
相关标签:
3条回答
  • 2020-12-03 17:32

    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.

    0 讨论(0)
  • 2020-12-03 17:39

    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.

    0 讨论(0)
  • 2020-12-03 17:47

    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.

    0 讨论(0)
提交回复
热议问题