Any way to properly pretty-print ordered dictionaries?

后端 未结 15 1485
春和景丽
春和景丽 2020-12-07 14:34

I like the pprint module in Python. I use it a lot for testing and debugging. I frequently use the width option to make sure the output fits nicely within my terminal window

相关标签:
15条回答
  • 2020-12-07 14:54

    This is pretty crude, but I just needed a way to visualize a data structure made up of any arbitrary Mappings and Iterables and this is what I came up with before giving up. It's recursive, so it will fall through nested structures and lists just fine. I used the Mapping and Iterable abstract base classes from collections to handle just about anything.

    I was aiming for almost yaml like output with concise python code, but didn't quite make it.

    def format_structure(d, level=0):
        x = ""
        if isinstance(d, Mapping):
            lenk = max(map(lambda x: len(str(x)), d.keys()))
            for k, v in d.items():
                key_text = "\n" + " "*level + " "*(lenk - len(str(k))) + str(k)
                x += key_text + ": " + format_structure(v, level=level+lenk)
        elif isinstance(d, Iterable) and not isinstance(d, basestring):
            for e in d:
                x += "\n" + " "*level + "- " + format_structure(e, level=level+4)
        else:
            x = str(d)
        return x
    

    and some test data using OrderedDict and lists of OrderedDicts... (sheesh Python needs OrderedDict literals sooo badly...)

    d = OrderedDict([("main",
                      OrderedDict([("window",
                                    OrderedDict([("size", [500, 500]),
                                                 ("position", [100, 900])])),
                                   ("splash_enabled", True),
                                   ("theme", "Dark")])),
                     ("updates",
                      OrderedDict([("automatic", True),
                                   ("servers",
                                    [OrderedDict([("url", "http://server1.com"),
                                                  ("name", "Stable")]),
                                     OrderedDict([("url", "http://server2.com"),
                                                  ("name", "Beta")]),
                                     OrderedDict([("url", "http://server3.com"),
                                                  ("name", "Dev")])]),
                                   ("prompt_restart", True)])),
                     ("logging",
                      OrderedDict([("enabled", True),
                                   ("rotate", True)]))])
    
    print format_structure(d)
    

    yields the following output:

       main: 
                   window: 
                             size: 
                                 - 500
                                 - 500
                         position: 
                                 - 100
                                 - 900
           splash_enabled: True
                    theme: Dark
    updates: 
                automatic: True
                  servers: 
                         - 
                              url: http://server1.com
                             name: Stable
                         - 
                              url: http://server2.com
                             name: Beta
                         - 
                              url: http://server3.com
                             name: Dev
           prompt_restart: True
    logging: 
           enabled: True
            rotate: True
    

    I had some thoughts along the way of using str.format() for better alignment, but didn't feel like digging into it. You'd need to dynamically specify the field widths depending on the type of alignment you want, which would get either tricky or cumbersome.

    Anyway, this shows me my data in readable hierarchical fashion, so that works for me!

    0 讨论(0)
  • 2020-12-07 14:56

    Here's another answer that works by overriding and using the stock pprint() function internally. Unlike my earlier one it will handle OrderedDict's inside another container such as a list and should also be able to handle any optional keyword arguments given — however it does not have the same degree of control over the output that the other one afforded.

    It operates by redirecting the stock function's output into a temporary buffer and then word wraps that before sending it on to the output stream. While the final output produced isn't exceptionalily pretty, it's decent and may be "good enough" to use as a workaround.

    Update 2.0

    Simplified by using standard library textwrap module, and modified to work in both Python 2 & 3.

    from collections import OrderedDict
    try:
        from cStringIO import StringIO
    except ImportError:  # Python 3
        from io import StringIO
    from pprint import pprint as pp_pprint
    import sys
    import textwrap
    
    def pprint(object, **kwrds):
        try:
            width = kwrds['width']
        except KeyError: # unlimited, use stock function
            pp_pprint(object, **kwrds)
            return
        buffer = StringIO()
        stream = kwrds.get('stream', sys.stdout)
        kwrds.update({'stream': buffer})
        pp_pprint(object, **kwrds)
        words = buffer.getvalue().split()
        buffer.close()
    
        # word wrap output onto multiple lines <= width characters
        try:
            print >> stream, textwrap.fill(' '.join(words), width=width)
        except TypeError:  # Python 3
            print(textwrap.fill(' '.join(words), width=width), file=stream)
    
    d = dict((('john',1), ('paul',2), ('mary',3)))
    od = OrderedDict((('john',1), ('paul',2), ('mary',3)))
    lod = [OrderedDict((('john',1), ('paul',2), ('mary',3))),
           OrderedDict((('moe',1), ('curly',2), ('larry',3))),
           OrderedDict((('weapons',1), ('mass',2), ('destruction',3)))]
    

    Sample output:

    pprint(d, width=40)
    

    »   {'john': 1, 'mary': 3, 'paul': 2}

    pprint(od, width=40)
    

    » OrderedDict([('john', 1), ('paul', 2),
       ('mary', 3)])

    pprint(lod, width=40)
    

    » [OrderedDict([('john', 1), ('paul', 2),
       ('mary', 3)]), OrderedDict([('moe', 1),
       ('curly', 2), ('larry', 3)]),
       OrderedDict([('weapons', 1), ('mass',
       2), ('destruction', 3)])]

    0 讨论(0)
  • 2020-12-07 15:01

    If the dictionary items are all of one type, you could use the amazing data-handling library pandas:

    >>> import pandas as pd
    >>> x = {'foo':1, 'bar':2}
    >>> pd.Series(x)
    bar    2
    foo    1
    dtype: int64
    

    or

    >>> import pandas as pd
    >>> x = {'foo':'bar', 'baz':'bam'}
    >>> pd.Series(x)
    baz    bam
    foo    bar
    dtype: object
    
    0 讨论(0)
  • 2020-12-07 15:02

    You can also use this simplification of the kzh answer:

    pprint(data.items(), indent=4)
    

    It preserves the order and will output almost the same than the webwurst answer (print through json dump).

    0 讨论(0)
  • 2020-12-07 15:03

    Here is my approach to pretty print an OrderedDict

    from collections import OrderedDict
    import json
    d = OrderedDict()
    d['duck'] = 'alive'
    d['parrot'] = 'dead'
    d['penguin'] = 'exploded'
    d['Falcon'] = 'discharged'
    print(d)
    print(json.dumps(d,indent=4))
    
    OutPut:
    
    OrderedDict([('duck', 'alive'), ('parrot', 'dead'), ('penguin', 'exploded'), ('Falcon', 'discharged')])
    
    {
        "duck": "alive",
        "parrot": "dead",
        "penguin": "exploded",
        "Falcon": "discharged"
    }
    

    If you want to pretty print dictionary with keys in sorted order

    print(json.dumps(indent=4,sort_keys=True))
    {
        "Falcon": "discharged",
        "duck": "alive",
        "parrot": "dead",
        "penguin": "exploded"
    }
    
    0 讨论(0)
  • 2020-12-07 15:05

    I've tested this unholy monkey-patch based hack on python3.5 and it works:

    pprint.PrettyPrinter._dispatch[pprint._collections.OrderedDict.__repr__] = pprint.PrettyPrinter._pprint_dict
    
    
    def unsorted_pprint(data):
        def fake_sort(*args, **kwargs):
            return args[0]
        orig_sorted = __builtins__.sorted
        try:
            __builtins__.sorted = fake_sort
            pprint.pprint(data)
        finally:
            __builtins__.sorted = orig_sorted
    

    You make pprint use the usual dict based summary and also disable sorting for the duration of the call so that no keys are actually sorted for printing.

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