Any way to properly pretty-print ordered dictionaries?

后端 未结 15 1483
春和景丽
春和景丽 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:49

    As a temporary workaround you can try dumping in JSON format. You lose some type information, but it looks nice and keeps the order.

    import json
    
    pprint(data, indent=4)
    # ^ugly
    
    print(json.dumps(data, indent=4))
    # ^nice
    
    0 讨论(0)
  • 2020-12-07 14:51

    To print an ordered dict, e.g.

    from collections import OrderedDict
    
    d=OrderedDict([
        ('a', OrderedDict([
            ('a1',1),
            ('a2','sss')
        ])),
        ('b', OrderedDict([
            ('b1', OrderedDict([
                ('bb1',1),
                ('bb2',4.5)])),
            ('b2',4.5)
        ])),
    ])
    

    I do

    def dict_or_OrdDict_to_formatted_str(OD, mode='dict', s="", indent=' '*4, level=0):
        def is_number(s):
            try:
                float(s)
                return True
            except ValueError:
                return False
        def fstr(s):
            return s if is_number(s) else '"%s"'%s
        if mode != 'dict':
            kv_tpl = '("%s", %s)'
            ST = 'OrderedDict([\n'; END = '])'
        else:
            kv_tpl = '"%s": %s'
            ST = '{\n'; END = '}'
        for i,k in enumerate(OD.keys()):
            if type(OD[k]) in [dict, OrderedDict]:
                level += 1
                s += (level-1)*indent+kv_tpl%(k,ST+dict_or_OrdDict_to_formatted_str(OD[k], mode=mode, indent=indent, level=level)+(level-1)*indent+END)
                level -= 1
            else:
                s += level*indent+kv_tpl%(k,fstr(OD[k]))
            if i!=len(OD)-1:
                s += ","
            s += "\n"
        return s
    
    print dict_or_OrdDict_to_formatted_str(d)
    

    Which yields

    "a": {
        "a1": 1,
        "a2": "sss"
    },
    "b": {
        "b1": {
            "bb1": 1,
            "bb2": 4.5
        },
        "b2": 4.5
    }
    

    or

    print dict_or_OrdDict_to_formatted_str(d, mode='OD')
    

    which yields

    ("a", OrderedDict([
        ("a1", 1),
        ("a2", "sss")
    ])),
    ("b", OrderedDict([
        ("b1", OrderedDict([
            ("bb1", 1),
            ("bb2", 4.5)
        ])),
        ("b2", 4.5)
    ]))
    
    0 讨论(0)
  • 2020-12-07 14:51
    def pprint_od(od):
        print "{"
        for key in od:
            print "%s:%s,\n" % (key, od[key]) # Fixed syntax
        print "}"
    

    There you go ^^

    for item in li:
        pprint_od(item)
    

    or

    (pprint_od(item) for item in li)
    
    0 讨论(0)
  • 2020-12-07 14:52

    For python < 3.8 (e.g. 3.6):

    Monkey patch pprint's sorted in order to prevent it from sorting. This will have the benefit of everything working recursively as well, and is more suitable than the json option for whoever needs to use e.g. width parameter:

    import pprint
    pprint.sorted = lambda arg, *a, **kw: arg
    
    >>> pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20)
    {'z': 1,
     'a': 2,
     'c': {'z': 0,
           'a': 1}}
    

    Edit: cleaning up

    To clean up after this dirty business just run: pprint.sorted = sorted

    For a really clean solution can even use a contextmanager:

    import pprint
    import contextlib
    
    @contextlib.contextmanager
    def pprint_ordered():
        pprint.sorted = lambda arg, *args, **kwargs: arg
        yield
        pprint.sorted = sorted
    
    # usage:
    
    with pprint_ordered():
        pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20)
    
    # without it    
    pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20)
    
    # prints: 
    #    
    # {'z': 1,
    #  'a': 2,
    #  'c': {'z': 0,
    #        'a': 1}}
    #
    # {'a': 2,
    #  'c': {'a': 1,
    #        'z': 0},
    #  'z': 1}
    
    0 讨论(0)
  • 2020-12-07 14:52

    You could redefine pprint() and intercept calls for OrderedDict's. Here's a simple illustration. As written, the OrderedDict override code ignores any optional stream, indent, width, or depth keywords that may have been passed, but could be enhanced to implement them. Unfortunately this technique doesn't handle them inside another container, such as a list of OrderDict's

    from collections import OrderedDict
    from pprint import pprint as pp_pprint
    
    def pprint(obj, *args, **kwrds):
        if not isinstance(obj, OrderedDict):
            # use stock function
            return pp_pprint(obj, *args, **kwrds)
        else:
            # very simple sample custom implementation...
            print "{"
            for key in obj:
                print "    %r:%r" % (key, obj[key])
            print "}"
    
    l = [10, 2, 4]
    d = dict((('john',1), ('paul',2), ('mary',3)))
    od = OrderedDict((('john',1), ('paul',2), ('mary',3)))
    pprint(l, width=4)
    # [10,
    #  2,
    #  4]
    pprint(d)
    # {'john': 1, 'mary': 3, 'paul': 2}
    
    pprint(od)
    # {
    #     'john':1
    #     'paul':2
    #     'mary':3
    # }
    
    0 讨论(0)
  • 2020-12-07 14:53

    Here’s a way that hacks the implementation of pprint. pprint sorts the keys before printing, so to preserve order, we just have to make the keys sort in the way we want.

    Note that this impacts the items() function. So you might want to preserve and restore the overridden functions after doing the pprint.

    from collections import OrderedDict
    import pprint
    
    class ItemKey(object):
      def __init__(self, name, position):
        self.name = name
        self.position = position
      def __cmp__(self, b):
        assert isinstance(b, ItemKey)
        return cmp(self.position, b.position)
      def __repr__(self):
        return repr(self.name)
    
    OrderedDict.items = lambda self: [
        (ItemKey(name, i), value)
        for i, (name, value) in enumerate(self.iteritems())]
    OrderedDict.__repr__ = dict.__repr__
    
    a = OrderedDict()
    a[4] = '4'
    a[1] = '1'
    a[2] = '2'
    print pprint.pformat(a) # {4: '4', 1: '1', 2: '2'}
    
    0 讨论(0)
提交回复
热议问题