Disabling sorting mechanism in pprint output

后端 未结 4 1281
鱼传尺愫
鱼传尺愫 2020-12-20 12:01

I have big dictionary which I`m printing for viewing with prettyprint, but how I can keep formatting but kill sorting mechanism in pprint?

相关标签:
4条回答
  • 2020-12-20 12:04

    I know that I am a bit late here but my preferred way to disable sorting dicts is by using partial:

    from functools import partial
    from pprint import pprint
    
    pprint = partial(pprint, sort_dicts=False)
    

    Personally I like this way as it introduces the smallest diffs.

    It has the benefit of monkey patching in that you only have to make changes at one spot(unlike other options) without having to mess with the internals of pprint.

    I'm using py3.8 but this should work from whenever sort_dicts option was added.

    0 讨论(0)
  • 2020-12-20 12:17

    You can subclass PrettyPrinter and remove the sorted(object.items()) from _pprint_dict.

    NOTE: this code is Python 3.5+

    # unsorted_pprint.py
    
    from pprint import PrettyPrinter, _builtin_scalars, _recursion
    
    __all__ = [
        'UnsortedPrettyPrinter',
        'pprint2',
        'pformat2',
    ]
    
    
    class UnsortedPrettyPrinter(PrettyPrinter):
        """Pretty printer that retains original dict ordering
        """
        def __init__(self, *args, **kwargs):
            super().__init__()
    
            self._dispatch = {
                **self._dispatch,
                dict.__repr__: self._pprint_dict,
            }
    
        @staticmethod
        def _pprint_dict(self, object, stream, indent, allowance, context, level):
            write = stream.write
            write('{')
            if self._indent_per_level > 1:
                write((self._indent_per_level - 1) * ' ')
            length = len(object)
            if length:
                items = object.items()
                self._format_dict_items(items, stream, indent, allowance + 1,
                                        context, level)
            write('}')
    
        def format(self, object, context, maxlevels, level):
            """Format object for a specific context, returning a string
            and flags indicating whether the representation is 'readable'
            and whether the object represents a recursive construct.
            """
            return self._safe_repr(object, context, maxlevels, level)
    
        def _safe_repr(self, object, context, maxlevels, level):
            typ = type(object)
            if typ in _builtin_scalars:
                return repr(object), True, False
    
            r = getattr(typ, "__repr__", None)
            if issubclass(typ, dict) and r is dict.__repr__:
                if not object:
                    return "{}", True, False
                objid = id(object)
                if maxlevels and level >= maxlevels:
                    return "{...}", False, objid in context
                if objid in context:
                    return _recursion(object), False, True
                context[objid] = 1
                readable = True
                recursive = False
                components = []
                append = components.append
                level += 1
                saferepr = self._safe_repr
                items = object.items()
                for k, v in items:
                    krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
                    vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
                    append("%s: %s" % (krepr, vrepr))
                    readable = readable and kreadable and vreadable
                    if krecur or vrecur:
                        recursive = True
                del context[objid]
                return "{%s}" % ", ".join(components), readable, recursive
    
            if (issubclass(typ, list) and r is list.__repr__) or \
                (issubclass(typ, tuple) and r is tuple.__repr__):
                if issubclass(typ, list):
                    if not object:
                        return "[]", True, False
                    format = "[%s]"
                elif len(object) == 1:
                    format = "(%s,)"
                else:
                    if not object:
                        return "()", True, False
                    format = "(%s)"
                objid = id(object)
                if maxlevels and level >= maxlevels:
                    return format % "...", False, objid in context
                if objid in context:
                    return _recursion(object), False, True
                context[objid] = 1
                readable = True
                recursive = False
                components = []
                append = components.append
                level += 1
                for o in object:
                    orepr, oreadable, orecur = self._safe_repr(o, context, maxlevels, level)
                    append(orepr)
                    if not oreadable:
                        readable = False
                    if orecur:
                        recursive = True
                del context[objid]
                return format % ", ".join(components), readable, recursive
    
            rep = repr(object)
            return rep, (rep and not rep.startswith('<')), False
    
    
    def pprint2(object, stream=None, indent=1, width=80, depth=None, *,
               compact=False):
        """Pretty-print a Python object to a stream [default is sys.stdout].
    
        dict items are left unsorted.
        """
        printer = UnsortedPrettyPrinter(
            stream=stream,
            indent=indent,
            width=width,
            depth=depth,
            compact=compact,
        )
        printer.pprint(object)
    
    
    def pformat2(object, indent=1, width=80, depth=None, *, compact=False):
        """Format a Python object into a pretty-printed representation.
    
        dict items are left unsorted.
        """
        return UnsortedPrettyPrinter(
            indent=indent,
            width=width,
            depth=depth,
            compact=compact,
        ).pformat(object)
    
    0 讨论(0)
  • 2020-12-20 12:20

    You can monkey patch the pprint module.

    import pprint
    
    pprint.pprint({"def":2,"ghi":3,"abc":1,})
    pprint._sorted = lambda x:x
    # Or, for Python 3.7:
    # pprint.sorted = lambda x, key=None: x
    pprint.pprint({"def":2,"ghi":3, "abc":1})
    

    Since the 2nd output is essentiallly randomly sorted, your output may be different from mine:

    {'abc': 1, 'def': 2, 'ghi': 3}
    {'abc': 1, 'ghi': 3, 'def': 2}
    


    Another version that is more complex, but easier to use:

    import pprint
    import contextlib
    
    @contextlib.contextmanager
    def pprint_nosort():
        # Note: the pprint implementation changed somewhere
        # between 2.7.12 and 3.7.0. This is the danger of
        # monkeypatching!
        try:
            # Old pprint
            orig,pprint._sorted = pprint._sorted, lambda x:x
        except AttributeError:
            # New pprint
            import builtins
            orig,pprint.sorted = None, lambda x, key=None:x
    
        try:
            yield
        finally:
            if orig:
                pprint._sorted = orig
            else:
                del pprint.sorted
    
    # For times when you don't want sorted output
    with pprint_nosort():
        pprint.pprint({"def":2,"ghi":3, "abc":1})
    
    # For times when you do want sorted output
    pprint.pprint({"def":2,"ghi":3, "abc":1})
    
    0 讨论(0)
  • 2020-12-20 12:30

    As of Python 3.8, you can finally disable this. Note that dictionaries are insertion-ordered since Python 3.7 (and in practice, even since 3.6).

    import pprint
    
    data = {'not': 'sorted', 'awesome': 'dict', 'z': 3, 'y': 2, 'x': 1}
    pprint.pprint(data, sort_dicts=False)
    # prints {'not': 'sorted', 'awesome': 'dict', 'z': 3, 'y': 2, 'x': 1}
    

    Alternatively, create a pretty printer object:

    pp = pprint.PrettyPrinter(sort_dicts=False)
    pp.pprint(data)
    

    This does not affect sets (which are still sorted), but then sets do not have insertion-ordering guarantees.

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