42

I use this code to pretty print a dict into JSON:

import json
d = {'a': 'blah', 'b': 'foo', 'c': [1,2,3]}
print json.dumps(d, indent = 2, separators=(',', ': '))

Output:

{
  "a": "blah",
  "c": [
    1,
    2,
    3
  ],
  "b": "foo"
}

This is a little bit too much (newline for each list element!).

Which syntax should I use to have this:

{
  "a": "blah",
  "c": [1, 2, 3],
  "b": "foo"
}

instead?

Pika Supports Ukraine
  • 3,612
  • 10
  • 26
  • 42
Basj
  • 41,386
  • 99
  • 383
  • 673
  • 2
    This isn't exactly an answer to your question, but if you're just looking for a data format that's easy on the eyes, you might try YAML. There are two syntaxes for collections like lists and dictionaries, "block" (where indentation shows the nesting) and "flow" (where brackets do that job). By default the output from PyYAML uses "flow" syntax for lists and dictionaries that don't contain any other containers, which sounds like exactly what you want for your pretty printing. – Blckknght Feb 18 '14 at 22:44
  • Thanks @Blckknght. Is YAML mature/stable/portable and likely to be available in the future years/future versions of python? Is it going to be a standard? (sorry for all these questions ;) ) – Basj Feb 18 '14 at 22:49
  • Another remark: I wanted to avoid conversion into string, because when I `load` back my JSON file into a `dict`, if it is a string, I don't have access anymore to the `list` (or I would need to parse the string into list but that's a shame to have to do this ...) – Basj Feb 18 '14 at 22:52
  • There's *gotta* be a way to do this by subclassing [`json.JSONEncoder`](http://docs.python.org/2/library/json.html#json.JSONEncoder), but I haven't figured it out. – ford Feb 18 '14 at 22:57
  • 1
    @Basj: I'm not really a YAML expert, but my understanding is that it's pretty stable and mature, though not nearly as widely used as JSON. You can find its standards at [the official YAML website](http://yaml.org), though the [Wikipedia page](http://en.wikipedia.org/wiki/YAML) seems quite a bit better at giving an overview. JSON is a subset of the latest version of YAML (and the incompatibilities with earlier YAML versions were apparently rarely encountered). – Blckknght Feb 19 '14 at 02:33
  • Is the display of `list`s the only formatting you want to customize (relative to the [table](http://docs.python.org/2/library/json.html#json.JSONEncoder) in the documentation showing the defualt Python types the built-in `json.JSONEncoder` class handles)? – martineau Feb 20 '14 at 09:31
  • @martineau yes `list` is the only formatting I want to customize – Basj Feb 20 '14 at 10:49
  • What should happen, indenting-wise, if the list contains a dictionary or another list, etc? – martineau Mar 18 '14 at 12:19
  • @martineau, both solutions would be okay for me (i.e. new lines for each sublist of the list, or no new line at all) – Basj Mar 18 '14 at 12:44
  • AFAICT there just isn't a reasonable way to do this with the built-in `JSONEncoder` class directly or subclassing, or even monkey-patching it that would meet your requirements. So you'll likely need to write your own, as @Shan Valleru suggests. – martineau Mar 21 '14 at 16:01
  • `json` is not the only module that can handle this for you. Maybe there is a reason this wasnt mentioned, I will admit I'm not a python guy. https://docs.python.org/3.2/library/pprint.html#module-pprint –  Dec 01 '14 at 15:31

6 Answers6

28

I ended up using jsbeautifier:

import jsbeautifier
opts = jsbeautifier.default_options()
opts.indent_size = 2
jsbeautifier.beautify(json.dumps(d), opts)

Output:

{
  "a": "blah",
  "c": [1, 2, 3],
  "b": "foo"
}
Allen Z.
  • 1,560
  • 1
  • 11
  • 19
6

Another alternative is print(json.dumps(d, indent=None, separators=(',\n', ': ')))

The output will be:

{"a": "blah",
"c": [1,
2,
3],
"b": "foo"}

Note that though the official docs at https://docs.python.org/2.7/library/json.html#basic-usage say the default args are separators=None --that actually means "use default of separators=(', ',': ') ). Note also that the comma separator doesn't distinguish between k/v pairs and list elements.

MarkHu
  • 1,694
  • 16
  • 29
  • 1
    Thanks but this is not exactly what was required; we would like to have `[1, 2, 3]` in a single line instead – Basj Sep 23 '15 at 12:20
  • Right, it isn't perfect, but it is lean and mean compared to the other monstrosities. ;) If I was going to get fancy, I'd use https://pypi.python.org/pypi/jq/ – MarkHu Sep 24 '15 at 04:22
  • 1
    Tnx for separators, helped me for lua compatibility. In lua no space is allowed. – josifoski Sep 09 '16 at 08:29
6

After years, I found a solution with the built-in pprint module:

import pprint
d = {'a': 'blah', 'b': 'foo', 'c': [1,2,3]}
pprint.pprint(d)                    # default width=80 so this will be printed in a single line
pprint.pprint(d, width=20)          # here it will be wrapped exactly as expected

Output:

{'a': 'blah',  
 'b': 'foo',  
 'c': [1, 2, 3]}

Basj
  • 41,386
  • 99
  • 383
  • 673
  • 3
    This isn't necessarily valid JSON, this is a pretty-printed Python dictionary that happens to usually be valid JSON. – Anonymous Nov 20 '20 at 23:06
  • @Anonymous You're right, but please note my question was explicitely about pretty-printing, but not about being a valid JSON string. – Basj Nov 21 '20 at 06:59
  • While the intent of your question might not have been about creating a valid JSON string it (especially due to the title) reads as such. Single quotes are definitely not valid JSON. So it is about pretty printing a dictionary, but not about pretty printing JSON? – t.niese Feb 20 '23 at 08:45
0

I couldn't get jsbeautifier to do much, so I used regular expressions. Had json pattern like

'{\n    "string": [\n        4,\n        1.0,\n        6,\n        1.0,\n        8,\n        1.0,\n        9,\n        1.0\n    ],\n...'

that I wanted as

'{\n    "string": [ 4, 1.0, 6, 1.0, 8, 1.0, 9, 1.0],\n'

so

t = json.dumps(apriori, indent=4)
t = re.sub('\[\n {7}', '[', t)
t = re.sub('(?<!\]),\n {7}', ',', t)
t = re.sub('\n {4}\]', ']', t)
outfile.write(t)

So instead of one "dump(apriori, t, indent=4)", I had those 5 lines.

  • 2
    Welcome @ChrisChang to StackOverflow! This seems more like a new question than an answer to this actual question. Can you please post it as a [new question](https://stackoverflow.com/questions/ask)? – Basj Jan 28 '21 at 19:30
  • Hi @Basj, thanks. This was a response to the root question (Pretty Print JSON Dumps), but I was referencing Allen Z's post about jsbeautifier. Perhaps I should have put the response inline with his answer, but the comment about jsbeautifier was tangential. – user15118385 Jan 31 '21 at 19:51
-2

This has been bugging me for a while as well, I found a 1 liner I'm almost happy with:

print json.dumps(eval(str(d).replace('[', '"[').replace(']', ']"').replace('(', '"(').replace(')', ')"')), indent=2).replace('\"\\"[', '[').replace(']\\"\"', ']').replace('\"\\"(', '(').replace(')\\"\"', ')')

That essentially convert all lists or tuples to a string, then uses json.dumps with indent to format the dict. Then you just need to remove the quotes and your done!

Note: I convert the dict to string to easily convert all lists/tuples no matter how nested the dict is.

PS. I hope the Python Police won't come after me for using eval... (use with care)

Tickon
  • 1,058
  • 1
  • 16
  • 25
-3

Perhaps not quite as efficient, but consider a simpler case (somewhat tested in Python 3, but probably would work in Python 2 also):

def dictJSONdumps( obj, levels, indentlevels = 0 ):
    import json
    if isinstance( obj, dict ):
        res = []
        for ix in sorted( obj, key=lambda x: str( x )):
            temp = ' ' * indentlevels + json.dumps( ix, ensure_ascii=False ) + ': '
            if levels:
                temp += dictJSONdumps( obj[ ix ], levels-1, indentlevels+1 )
            else:
                temp += json.dumps( obj[ ix ], ensure_ascii=False )
            res.append( temp )
        return '{\n' + ',\n'.join( res ) + '\n}'
    else:
        return json.dumps( obj, ensure_ascii=False )

This might give you some ideas, short of writing your own serializer completely. I used my own favorite indent technique, and hard-coded ensure_ascii, but you could add parameters and pass them along, or hard-code your own, etc.

Victoria
  • 497
  • 2
  • 10
  • 20