Tengo un gran diccionario que estoy imprimiendo para ver con prettyprint, pero ¿cómo puedo seguir formateando pero matando el mecanismo de clasificación en pprint?

17
Edd 5 sep. 2014 a las 13:50

3 respuestas

La mejor respuesta

Puede parche de mono el módulo pprint.

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})

Dado que la segunda salida está clasificada aleatoriamente al azar, su salida puede ser diferente de la mía:

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

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})
9
Robᵩ 24 jun. 2019 a las 19:53

Puede subclasificar PrettyPrinter y eliminar sorted(object.items()) de _pprint_dict.

NOTA: este código es 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
SmartManoj 26 jun. 2019 a las 09:33

A partir de Python 3.8, finalmente puede desactivar esto. Tenga en cuenta que los diccionarios están ordenados por inserción desde Python 3.7 (y en la práctica, incluso desde 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}

Alternativamente, cree un bonito objeto de impresora:

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

Esto no afecta a los conjuntos (que todavía están ordenados), pero luego los conjuntos no tienen garantías de orden de inserción.

3
Norrius 11 dic. 2019 a las 20:30