¿Cómo imprimir bonitos diccionarios anidados?

289

¿Cómo puedo imprimir un diccionario con una profundidad de ~ 4 en Python? Intenté imprimir bien con pprint(), pero no funcionó:

import pprint 
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(mydict)

Simplemente quiero una sangría ( "\t") para cada anidamiento, para obtener algo como esto:

key1
    value1
    value2
    key2
       value1
       value2

etc.

¿Cómo puedo hacer esto?

Martineau
fuente
29
¿Qué significa "no funcionó"? Especifique con mucha precisión cómo pprint "no funcionó".
S.Lott
55
Ahora he usado 3 de estas respuestas (cada una buena en un escenario específico): la respuesta json de @ Ken es buena pero a veces falla cuando el objeto no puede ser serializable json (produce una excepción). si la respuesta json de @ Ken no funciona, pruebe la respuesta yaml de @ Andy y debería funcionar, pero la salida de la cadena es un poco menos legible para los humanos. [la respuesta de @ sth] es la más genérica (debería funcionar para cualquier objeto y no usa ninguna libs).
Trevor Boyd Smith

Respuestas:

143

No estoy seguro de cómo desea exactamente que se vea el formato, pero podría comenzar con una función como esta:

def pretty(d, indent=0):
   for key, value in d.items():
      print('\t' * indent + str(key))
      if isinstance(value, dict):
         pretty(value, indent+1)
      else:
         print('\t' * (indent+1) + str(value))
algo
fuente
8
La respuesta convencional de U know @ Ken es mucho mejor que esta. Json ya maneja todo y esto puede dar errores como: UnicodeEncodeError: el códec 'ascii' no puede codificar el carácter u '\ xf3' en la posición 50: ordinal no está en el rango (128)
pregunto por qué
No puedo hacer que funcione con el dict anidado de mi solución, porque me dio un UnicodeEncodeError, tampoco imprime la clave dict, no va dentro de la lista y las tuplas y no mantiene una sintaxis válida de Python.
y.petremann
Esta respuesta funcionó de maravilla para mí, sin embargo, publiqué una nueva pregunta stackoverflow.com/questions/36972225/… que establece un límite para la cantidad de valores que se deben imprimir.
gsamaras
Bastante bueno. Si tiene listas anidadas como en la pregunta del OP, debe agregar algo de manejo para eso. Si tiene problemas en Py2, es porque no puede manejar Unicode correctamente sin hacks como el __future__que ahora menciona la respuesta, por lo que debe emplearlos donde sea necesario (o actualizar a 3 ya).
sudo
Esto funcionó bastante bien para mí: python def pretty(d, indent=0): for key, value in d.items(): if isinstance(value, dict): print(' ' * indent + str(key)) pretty(value, indent+1) else: print(' ' * (indent+1) + f"{key}: {value}")
hum3
500

Lo primero que pensé fue que el serializador JSON probablemente sea bastante bueno en los diccionarios anidados, por lo que haría trampa y usaría eso:

>>> import json
>>> print json.dumps({'a':2, 'b':{'x':3, 'y':{'t1': 4, 't2':5}}},
...                  sort_keys=True, indent=4)
{
    "a": 2,
    "b": {
        "x": 3,
        "y": {
            "t1": 4,
            "t2": 5
        }
    }
}
Conocido
fuente
40
Esto es genial, pero no imprime bien todos los diccionarios. print json.dumps (myObject .__ dict__, sort_keys = True, indent = 4) #TypeError: <object at 0x0000000002E6A748> no es serializable JSON
tponthieux
44
Si bien esto parece útil, su salida no es lo que el OP quería.
Martineau
2
@martineau: la salida solicitada del OP no tiene sentido, los diccionarios necesitan claves por valor.
naught101
2
@ naught101: una impresora bonita puede hacer lo que sea necesario para producir el resultado deseado.
Martineau
22
json.dumps toma una función de conversión como argumento opcional, por lo que con json.dumps (myObject .__ dict__, sort_keys = True, indent = 4, deault = str) puede al menos usar una implementación de objetos de repr para imprimir y moverse el TypeError 'no serializable JSON'
RFairey
56

Puedes probar YAML a través de PyYAML . Su salida se puede ajustar. Sugeriría comenzar con lo siguiente:

print yaml.dump(data, allow_unicode=True, default_flow_style=False)

El resultado es muy legible; también se puede analizar de nuevo a Python si es necesario.

Editar:

Ejemplo:

>>> import yaml
>>> data = {'a':2, 'b':{'x':3, 'y':{'t1': 4, 't2':5}}}
>>> print yaml.dump(data, default_flow_style=False)
a: 2
b:
  x: 3
  y:
    t1: 4
    t2: 5
Andy Mikhaylenko
fuente
1
Usar yaml es muy interesante porque mantiene el tipo de datos sobre su formato, lo único que puedo decir en contra es que no produce una cadena de python válida, pero casi se puede convertir de nuevo en python.
y.petremann
1
yaml no le gusta la versión de Numpy de tipos escalares ... No me sorprendió que no admite matrices numpy, pero yo hubiera esperado la misma salida para una floaty unanumpy.float64
PhilMacKay
este enfoque también funcionó para mí usando una lista de diccionarios
Grant Shannon
36

A partir de lo que se ha hecho, no veo ninguna impresora bonita que al menos imite la salida del intérprete de Python con un formato muy simple, así que aquí está el mío:

class Formatter(object):
    def __init__(self):
        self.types = {}
        self.htchar = '\t'
        self.lfchar = '\n'
        self.indent = 0
        self.set_formater(object, self.__class__.format_object)
        self.set_formater(dict, self.__class__.format_dict)
        self.set_formater(list, self.__class__.format_list)
        self.set_formater(tuple, self.__class__.format_tuple)

    def set_formater(self, obj, callback):
        self.types[obj] = callback

    def __call__(self, value, **args):
        for key in args:
            setattr(self, key, args[key])
        formater = self.types[type(value) if type(value) in self.types else object]
        return formater(self, value, self.indent)

    def format_object(self, value, indent):
        return repr(value)

    def format_dict(self, value, indent):
        items = [
            self.lfchar + self.htchar * (indent + 1) + repr(key) + ': ' +
            (self.types[type(value[key]) if type(value[key]) in self.types else object])(self, value[key], indent + 1)
            for key in value
        ]
        return '{%s}' % (','.join(items) + self.lfchar + self.htchar * indent)

    def format_list(self, value, indent):
        items = [
            self.lfchar + self.htchar * (indent + 1) + (self.types[type(item) if type(item) in self.types else object])(self, item, indent + 1)
            for item in value
        ]
        return '[%s]' % (','.join(items) + self.lfchar + self.htchar * indent)

    def format_tuple(self, value, indent):
        items = [
            self.lfchar + self.htchar * (indent + 1) + (self.types[type(item) if type(item) in self.types else object])(self, item, indent + 1)
            for item in value
        ]
        return '(%s)' % (','.join(items) + self.lfchar + self.htchar * indent)

Para inicializarlo:

pretty = Formatter()

Puede admitir la adición de formateadores para tipos definidos, simplemente necesita hacer una función para eso como esta y vincularla al tipo que desee con set_formater:

from collections import OrderedDict

def format_ordereddict(self, value, indent):
    items = [
        self.lfchar + self.htchar * (indent + 1) +
        "(" + repr(key) + ', ' + (self.types[
            type(value[key]) if type(value[key]) in self.types else object
        ])(self, value[key], indent + 1) + ")"
        for key in value
    ]
    return 'OrderedDict([%s])' % (','.join(items) +
           self.lfchar + self.htchar * indent)
pretty.set_formater(OrderedDict, format_ordereddict)

Por razones históricas, mantengo la bonita impresora anterior, que era una función en lugar de una clase, pero ambas se pueden usar de la misma manera, la versión de clase simplemente permite mucho más:

def pretty(value, htchar='\t', lfchar='\n', indent=0):
    nlch = lfchar + htchar * (indent + 1)
    if type(value) is dict:
        items = [
            nlch + repr(key) + ': ' + pretty(value[key], htchar, lfchar, indent + 1)
            for key in value
        ]
        return '{%s}' % (','.join(items) + lfchar + htchar * indent)
    elif type(value) is list:
        items = [
            nlch + pretty(item, htchar, lfchar, indent + 1)
            for item in value
        ]
        return '[%s]' % (','.join(items) + lfchar + htchar * indent)
    elif type(value) is tuple:
        items = [
            nlch + pretty(item, htchar, lfchar, indent + 1)
            for item in value
        ]
        return '(%s)' % (','.join(items) + lfchar + htchar * indent)
    else:
        return repr(value)

Para usarlo:

>>> a = {'list':['a','b',1,2],'dict':{'a':1,2:'b'},'tuple':('a','b',1,2),'function':pretty,'unicode':u'\xa7',("tuple","key"):"valid"}
>>> a
{'function': <function pretty at 0x7fdf555809b0>, 'tuple': ('a', 'b', 1, 2), 'list': ['a', 'b', 1, 2], 'dict': {'a': 1, 2: 'b'}, 'unicode': u'\xa7', ('tuple', 'key'): 'valid'}
>>> print(pretty(a))
{
    'function': <function pretty at 0x7fdf555809b0>,
    'tuple': (
        'a',
        'b',
        1,
        2
    ),
    'list': [
        'a',
        'b',
        1,
        2
    ],
    'dict': {
        'a': 1,
        2: 'b'
    },
    'unicode': u'\xa7',
    ('tuple', 'key'): 'valid'
}

En comparación con otras versiones:

  • Esta solución busca directamente el tipo de objeto, por lo que puede imprimir casi todo, no solo listar o dictar.
  • No tiene ninguna dependencia.
  • Todo se coloca dentro de una cadena, para que pueda hacer lo que quiera con él.
  • La clase y la función han sido probadas y funcionan con Python 2.7 y 3.4.
  • Puede tener todo tipo de objetos dentro, estas son sus representaciones y no sus contenidos que se ponen en el resultado (por lo que las cadenas tienen comillas, las cadenas Unicode están totalmente representadas ...).
  • Con la versión de clase, puede agregar formato para cada tipo de objeto que desee o cambiarlos por los ya definidos.
  • La clave puede ser de cualquier tipo válido.
  • El carácter de sangría y nueva línea se puede cambiar por todo lo que nos gustaría.
  • Dict, List y Tuples están bastante impresos.
y.petremann
fuente
2
Esta definitivamente debería ser la solución aceptada: la falta de dependencia de JSON es enorme.
Josh
sería genial si pudiera hacer objetos convirtiéndolos en dictados y configurando su clave para que sea el tipo de objeto
Alex Cory
Básicamente, puede reemplazar el método format_object interno o externo para hacerlo.
y.petremann
set_formater - necesita dos t, esto es un error tipográfico, debe formateador
Nikolay Prokopyev
32

de esta manera puede imprimirlo de manera bonita, por ejemplo, el nombre de su diccionario es yasin

import json

print (json.dumps(yasin, indent=2))
yasin lachini
fuente
55
Esto supone que el contenido del diccionario es json serializable, lo cual no es necesariamente cierto.
SpiXel
8

Otra opción con yapf:

from pprint import pformat
from yapf.yapflib.yapf_api import FormatCode

dict_example = {'1': '1', '2': '2', '3': [1, 2, 3, 4, 5], '4': {'1': '1', '2': '2', '3': [1, 2, 3, 4, 5]}}
dict_string = pformat(dict_example)
formatted_code, _ = FormatCode(dict_string)

print(formatted_code)

Salida:

{
    '1': '1',
    '2': '2',
    '3': [1, 2, 3, 4, 5],
    '4': {
        '1': '1',
        '2': '2',
        '3': [1, 2, 3, 4, 5]
    }
}
Eyal Levin
fuente
5

Como otros han publicado, puede usar recursividad / dfs para imprimir los datos del diccionario anidados y llamar recursivamente si es un diccionario; de lo contrario imprima los datos.

def print_json(data):
    if type(data) == dict:
            for k, v in data.items():
                    print k
                    print_json(v)
    else:
            print data
Rohit Malgaonkar
fuente
5

Una de las formas más pitónicas para eso es usar el módulo pprint ya construido .

El argumento que necesita para definir la profundidad de impresión es el que puede esperar. depth

import pprint
pp = pprint.PrettyPrinter(depth=4)
pp.pprint(mydict)

Eso es !

Juan Kabbali
fuente
4

pout puede imprimir cualquier cosa que le arrojes, por ejemplo (tomando prestado datade otra respuesta):

data = {'a':2, 'b':{'x':3, 'y':{'t1': 4, 't2':5}}}
pout.vs(data)

daría como resultado una salida impresa en la pantalla como:

{
    'a': 2,
    'b':
    {
        'y':
        {
            't2': 5,
            't1': 4
        },
        'x': 3
    }
}

o puede devolver la salida de cadena formateada de su objeto:

v = pout.s(data)

Su caso de uso principal es para la depuración, por lo que no se ahoga en instancias de objetos ni nada y maneja la salida unicode como era de esperar, funciona en python 2.7 y 3.

divulgación : soy el autor y mantenedor de pout.

Jaymon
fuente
3

Tomé la respuesta de sth y la modifiqué ligeramente para satisfacer mis necesidades de diccionarios y listas anidados:

def pretty(d, indent=0):
    if isinstance(d, dict):
        for key, value in d.iteritems():
            print '\t' * indent + str(key)
            if isinstance(value, dict) or isinstance(value, list):
                pretty(value, indent+1)
            else:
                print '\t' * (indent+1) + str(value)
    elif isinstance(d, list):
        for item in d:
            if isinstance(item, dict) or isinstance(item, list):
                pretty(item, indent+1)
            else:
                print '\t' * (indent+1) + str(item)
    else:
        pass

Lo que luego me da salida como:

>>> 
xs:schema
    @xmlns:xs
        http://www.w3.org/2001/XMLSchema
    xs:redefine
        @schemaLocation
            base.xsd
        xs:complexType
            @name
                Extension
            xs:complexContent
                xs:restriction
                    @base
                        Extension
                    xs:sequence
                        xs:element
                            @name
                                Policy
                            @minOccurs
                                1
                            xs:complexType
                                xs:sequence
                                    xs:element
                                            ...
Jamie Ivanov
fuente
1

Sth, me hundo, eso es bonito;)

def pretty(d, indent=0):
    for key, value in d.iteritems():
        if isinstance(value, dict):
            print '\t' * indent + (("%30s: {\n") % str(key).upper())
            pretty(value, indent+1)
            print '\t' * indent + ' ' * 32 + ('} # end of %s #\n' % str(key).upper())
        elif isinstance(value, list):
            for val in value:
                print '\t' * indent + (("%30s: [\n") % str(key).upper())
                pretty(val, indent+1)
                print '\t' * indent + ' ' * 32 + ('] # end of %s #\n' % str(key).upper())
        else:
            print '\t' * indent + (("%30s: %s") % (str(key).upper(),str(value)))
VindeX
fuente
1
-1: no maneja listvalores que no son dictinstancias, es decir pretty({'key': [1, 2, 3]}, indent=4)==> AttributeError: 'int' object has no attribute 'iteritems'. Tampoco me gusta mayúsculas.
Martineau
Su solución considera que no puede haber un dict dentro de una lista dentro del dict raíz. También considera que no queremos imprimir una lista o una tupla. Finalmente, no capitalice las claves, el resultado para {'a': 0, 'A': 1} no sería correcto.
y.petremann
1
This class prints out a complex nested dictionary with sub dictionaries and sub lists.  
##
## Recursive class to parse and print complex nested dictionary
##

class NestedDictionary(object):
    def __init__(self,value):
        self.value=value

    def print(self,depth):
        spacer="--------------------"
        if type(self.value)==type(dict()):
            for kk, vv in self.value.items():
                if (type(vv)==type(dict())):
                    print(spacer[:depth],kk)
                    vvv=(NestedDictionary(vv))
                    depth=depth+3
                    vvv.print(depth)
                    depth=depth-3
                else:
                    if (type(vv)==type(list())):
                        for i in vv:
                            vvv=(NestedDictionary(i))
                            depth=depth+3
                            vvv.print(depth)
                            depth=depth-3
                    else:
                        print(spacer[:depth],kk,vv) 

##
## Instatiate and execute - this prints complex nested dictionaries
## with sub dictionaries and sub lists
## 'something' is a complex nested dictionary

MyNest=NestedDictionary(weather_com_result)
MyNest.print(0)
Bob Lockwood
fuente
1

Escribí este código simple para imprimir la estructura general de un objeto json en Python.

def getstructure(data, tab = 0):
    if type(data) is dict:
        print ' '*tab + '{' 
        for key in data:
            print ' '*tab + '  ' + key + ':'
            getstructure(data[key], tab+4)
        print ' '*tab + '}'         
    elif type(data) is list and len(data) > 0:
        print ' '*tab + '['
        getstructure(data[0], tab+4)
        print ' '*tab + '  ...'
        print ' '*tab + ']'

el resultado para los siguientes datos

a = {'list':['a','b',1,2],'dict':{'a':1,2:'b'},'tuple':('a','b',1,2),'function':'p','unicode':u'\xa7',("tuple","key"):"valid"}
getstructure(a)

es muy compacto y se ve así:

{
  function:
  tuple:
  list:
    [
      ...
    ]
  dict:
    {
      a:
      2:
    }
  unicode:
  ('tuple', 'key'):
}
Abtin Rasoulian
fuente
0

Soy un novato en Python, pero he estado trabajando con diccionarios anidados durante las últimas dos semanas y esto es lo que se me ocurrió.

Deberías intentar usar una pila. Convierta las claves del diccionario raíz en una lista de una lista:

stack = [ root.keys() ]     # Result: [ [root keys] ]

Yendo en orden inverso de último a primero, busque cada clave en el diccionario para ver si su valor es (también) un diccionario. Si no, imprima la clave y luego bórrela. Sin embargo, si el valor de la clave es un diccionario, imprima la clave, luego agregue las claves para ese valor al final de la pila y comience a procesar esa lista de la misma manera, repitiendo recursivamente para cada nueva lista de claves.

Si el valor de la segunda clave en cada lista fuera un diccionario, tendría algo como esto después de varias rondas:

[['key 1','key 2'],['key 2.1','key 2.2'],['key 2.2.1','key 2.2.2'],[`etc.`]]

La ventaja de este enfoque es que la sangría es solo \tveces la longitud de la pila:

indent = "\t" * len(stack)

La desventaja es que para verificar cada clave, debe pasar al sub-diccionario relevante, aunque esto se puede manejar fácilmente con una comprensión de la lista y un forbucle simple :

path = [li[-1] for li in stack]
# The last key of every list of keys in the stack

sub = root
for p in path:
    sub = sub[p]


if type(sub) == dict:
    stack.append(sub.keys()) # And so on

Tenga en cuenta que este enfoque requerirá que limpie las listas vacías finales, y que elimine la última clave de cualquier lista seguida de una lista vacía (que, por supuesto, puede crear otra lista vacía, etc.).

Hay otras formas de implementar este enfoque, pero con suerte esto le dará una idea básica de cómo hacerlo.

EDITAR: si no desea pasar por todo eso, el pprintmódulo imprime diccionarios anidados en un formato agradable.

danwroy
fuente
0

Aquí hay una función que escribí en función del comentario de sth. Funciona igual que json.dumps con sangría, pero estoy usando pestañas en lugar de espacio para sangrías. En Python 3.2+ puede especificar que la sangría sea un '\ t' directamente, pero no en 2.7.

def pretty_dict(d):
    def pretty(d, indent):
        for i, (key, value) in enumerate(d.iteritems()):
            if isinstance(value, dict):
                print '{0}"{1}": {{'.format( '\t' * indent, str(key))
                pretty(value, indent+1)
                if i == len(d)-1:
                    print '{0}}}'.format( '\t' * indent)
                else:
                    print '{0}}},'.format( '\t' * indent)
            else:
                if i == len(d)-1:
                    print '{0}"{1}": "{2}"'.format( '\t' * indent, str(key), value)
                else:
                    print '{0}"{1}": "{2}",'.format( '\t' * indent, str(key), value)
    print '{'
    pretty(d,indent=1)
    print '}'

Ex:

>>> dict_var = {'a':2, 'b':{'x':3, 'y':{'t1': 4, 't2':5}}}
>>> pretty_dict(dict_var)
{
    "a": "2",
    "b": {
        "y": {
            "t2": "5",
            "t1": "4"
        },
        "x": "3"
    }
}
Al Conrad
fuente
No puedo hacer que funcione con el dictado anidado de mi solución, porque me dio un UnicodeEncodeError, también los elementos y las claves se convierten en cadenas, ¿qué pasa si usamos números o tuplas que contienen listas y dictados? Finalmente, su solución tenga en cuenta que nuestro objeto que queremos imprimir bonito debe ser un dict.
y.petremann
No estaba tratando de escribir una función de impresión genérica para un dict python. Los comentarios mejor calificados ya demuestran cómo imprimir un dict de forma bonita. Mi contribución fue escribir una alternativa a json.dumps con '\ t' para sangría en lugar de pestañas en python 2.7.
Al Conrad
Estoy de acuerdo con usted en escribir una alternativa a json.dumps, para mí se aplican los mismos problemas que a json.dumps. Además, puede usar una expresión regular simple para cambiar el tipo de sangría, haciendo que su código sea más simple.
y.petremann
0

Aquí hay algo que imprimirá cualquier tipo de diccionario anidado, mientras realiza un seguimiento de los diccionarios "principales" en el camino.

dicList = list()

def prettierPrint(dic, dicList):
count = 0
for key, value in dic.iteritems():
    count+=1
    if str(value) == 'OrderedDict()':
        value = None
    if not isinstance(value, dict):
        print str(key) + ": " + str(value)
        print str(key) + ' was found in the following path:',
        print dicList
        print '\n'
    elif isinstance(value, dict):
        dicList.append(key)
        prettierPrint(value, dicList)
    if dicList:
         if count == len(dic):
             dicList.pop()
             count = 0

prettierPrint(dicExample, dicList)

Este es un buen punto de partida para imprimir según diferentes formatos, como el especificado en OP. Todo lo que realmente necesita hacer es realizar operaciones alrededor de los bloques Imprimir . Tenga en cuenta que se ve para ver si el valor es 'OrderedDict ()'. Dependiendo de si está utilizando algo de las colecciones de tipos de datos de contenedor , debe hacer este tipo de seguridad para que el bloque elif no lo vea como un diccionario adicional debido a su nombre. A partir de ahora, un diccionario de ejemplo como

example_dict = {'key1': 'value1',
            'key2': 'value2',
            'key3': {'key3a': 'value3a'},
            'key4': {'key4a': {'key4aa': 'value4aa',
                               'key4ab': 'value4ab',
                               'key4ac': 'value4ac'},
                     'key4b': 'value4b'}

imprimirá

key3a: value3a
key3a was found in the following path: ['key3']

key2: value2
key2 was found in the following path: []

key1: value1
key1 was found in the following path: []

key4ab: value4ab
key4ab was found in the following path: ['key4', 'key4a']

key4ac: value4ac
key4ac was found in the following path: ['key4', 'key4a']

key4aa: value4aa
key4aa was found in the following path: ['key4', 'key4a']

key4b: value4b
key4b was found in the following path: ['key4']

~ alterar el código para que se ajuste al formato de la pregunta ~

lastDict = list()
dicList = list()
def prettierPrint(dic, dicList):
    global lastDict
    count = 0
    for key, value in dic.iteritems():
        count+=1
        if str(value) == 'OrderedDict()':
            value = None
        if not isinstance(value, dict):
            if lastDict == dicList:
                sameParents = True
            else:
                sameParents = False

            if dicList and sameParents is not True:
                spacing = ' ' * len(str(dicList))
                print dicList
                print spacing,
                print str(value)

            if dicList and sameParents is True:
                print spacing,
                print str(value)
            lastDict = list(dicList)

        elif isinstance(value, dict):
            dicList.append(key)
            prettierPrint(value, dicList)

        if dicList:
             if count == len(dic):
                 dicList.pop()
                 count = 0

Usando el mismo código de ejemplo, imprimirá lo siguiente:

['key3']
         value3a
['key4', 'key4a']
                  value4ab
                  value4ac
                  value4aa
['key4']
         value4b

Esto no es exactamente lo que se solicita en OP. La diferencia es que un padre ^ n todavía se imprime, en lugar de estar ausente y reemplazado con espacios en blanco. Para llegar al formato de OP, deberá hacer algo como lo siguiente: comparar iterativamente dicList con lastDict . Usted puede hacer esto haciendo un nuevo diccionario y copiar contenido de dicList a ella, comprobando si i en el diccionario copiado es lo mismo que yo en lastDict, y - si es - escritura espacio en blanco para que i posición usando la función de cadena multiplicador .

gavin
fuente
0

Desde este enlace :

def prnDict(aDict, br='\n', html=0,
            keyAlign='l',   sortKey=0,
            keyPrefix='',   keySuffix='',
            valuePrefix='', valueSuffix='',
            leftMargin=0,   indent=1 ):
    '''
return a string representive of aDict in the following format:
    {
     key1: value1,
     key2: value2,
     ...
     }

Spaces will be added to the keys to make them have same width.

sortKey: set to 1 if want keys sorted;
keyAlign: either 'l' or 'r', for left, right align, respectively.
keyPrefix, keySuffix, valuePrefix, valueSuffix: The prefix and
   suffix to wrap the keys or values. Good for formatting them
   for html document(for example, keyPrefix='<b>', keySuffix='</b>'). 
   Note: The keys will be padded with spaces to have them
         equally-wide. The pre- and suffix will be added OUTSIDE
         the entire width.
html: if set to 1, all spaces will be replaced with '&nbsp;', and
      the entire output will be wrapped with '<code>' and '</code>'.
br: determine the carriage return. If html, it is suggested to set
    br to '<br>'. If you want the html source code eazy to read,
    set br to '<br>\n'

version: 04b52
author : Runsun Pan
require: odict() # an ordered dict, if you want the keys sorted.
         Dave Benjamin 
         http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/161403
    '''

    if aDict:

        #------------------------------ sort key
        if sortKey:
            dic = aDict.copy()
            keys = dic.keys()
            keys.sort()
            aDict = odict()
            for k in keys:
                aDict[k] = dic[k]

        #------------------- wrap keys with ' ' (quotes) if str
        tmp = ['{']
        ks = [type(x)==str and "'%s'"%x or x for x in aDict.keys()]

        #------------------- wrap values with ' ' (quotes) if str
        vs = [type(x)==str and "'%s'"%x or x for x in aDict.values()] 

        maxKeyLen = max([len(str(x)) for x in ks])

        for i in range(len(ks)):

            #-------------------------- Adjust key width
            k = {1            : str(ks[i]).ljust(maxKeyLen),
                 keyAlign=='r': str(ks[i]).rjust(maxKeyLen) }[1]

            v = vs[i]        
            tmp.append(' '* indent+ '%s%s%s:%s%s%s,' %(
                        keyPrefix, k, keySuffix,
                        valuePrefix,v,valueSuffix))

        tmp[-1] = tmp[-1][:-1] # remove the ',' in the last item
        tmp.append('}')

        if leftMargin:
          tmp = [ ' '*leftMargin + x for x in tmp ]

        if html:
            return '<code>%s</code>' %br.join(tmp).replace(' ','&nbsp;')
        else:
            return br.join(tmp)     
    else:
        return '{}'

'''
Example:

>>> a={'C': 2, 'B': 1, 'E': 4, (3, 5): 0}

>>> print prnDict(a)
{
 'C'   :2,
 'B'   :1,
 'E'   :4,
 (3, 5):0
}

>>> print prnDict(a, sortKey=1)
{
 'B'   :1,
 'C'   :2,
 'E'   :4,
 (3, 5):0
}

>>> print prnDict(a, keyPrefix="<b>", keySuffix="</b>")
{
 <b>'C'   </b>:2,
 <b>'B'   </b>:1,
 <b>'E'   </b>:4,
 <b>(3, 5)</b>:0
}

>>> print prnDict(a, html=1)
<code>{
&nbsp;'C'&nbsp;&nbsp;&nbsp;:2,
&nbsp;'B'&nbsp;&nbsp;&nbsp;:1,
&nbsp;'E'&nbsp;&nbsp;&nbsp;:4,
&nbsp;(3,&nbsp;5):0
}</code>

>>> b={'car': [6, 6, 12], 'about': [15, 9, 6], 'bookKeeper': [9, 9, 15]}

>>> print prnDict(b, sortKey=1)
{
 'about'     :[15, 9, 6],
 'bookKeeper':[9, 9, 15],
 'car'       :[6, 6, 12]
}

>>> print prnDict(b, keyAlign="r")
{
        'car':[6, 6, 12],
      'about':[15, 9, 6],
 'bookKeeper':[9, 9, 15]
}
'''
usuario2757572
fuente
0

Sólo estoy volviendo a esta pregunta después de tomar algo respuestas 's y hacer una pequeña pero muy útil modificación. Esta función imprime todas las claves en el árbol JSON , así como el tamaño de los nodos hoja en ese árbol.

def print_JSON_tree(d, indent=0):
    for key, value in d.iteritems():
        print '    ' * indent + unicode(key),
        if isinstance(value, dict):
            print; print_JSON_tree(value, indent+1)
        else:
            print ":", str(type(d[key])).split("'")[1], "-", str(len(unicode(d[key])))

Es realmente agradable cuando tienes grandes objetos JSON y quieres descubrir dónde está la carne. Ejemplo :

>>> print_JSON_tree(JSON_object)
key1
    value1 : int - 5
    value2 : str - 16
    key2
       value1 : str - 34
       value2 : list - 5623456

Esto le indicaría que la mayoría de los datos que le interesan probablemente estén dentro JSON_object['key1']['key2']['value2']porque la longitud de ese valor formateado como una cadena es muy grande.

Ulf Aslak
fuente
0

Utiliza esta función:

def pretty_dict(d, n=1):
    for k in d:
        print(" "*n + k)
        try:
            pretty_dict(d[k], n=n+4)
        except TypeError:
            continue

Llámalo así:

pretty_dict(mydict)
cincuenta y dos tarjetas
fuente
Esto no funciona si los valores son cadenas. Imprime cada carácter de la cadena en una nueva línea, pero las teclas parecen funcionar bien.
Anthony
0

Esto es lo que se me ocurrió mientras trabajaba en una clase que necesitaba escribir un diccionario en un archivo .txt:

@staticmethod
def _pretty_write_dict(dictionary):

    def _nested(obj, level=1):
        indentation_values = "\t" * level
        indentation_braces = "\t" * (level - 1)
        if isinstance(obj, dict):
            return "{\n%(body)s%(indent_braces)s}" % {
                "body": "".join("%(indent_values)s\'%(key)s\': %(value)s,\n" % {
                    "key": str(key),
                    "value": _nested(value, level + 1),
                    "indent_values": indentation_values
                } for key, value in obj.items()),
                "indent_braces": indentation_braces
            }
        if isinstance(obj, list):
            return "[\n%(body)s\n%(indent_braces)s]" % {
                "body": "".join("%(indent_values)s%(value)s,\n" % {
                    "value": _nested(value, level + 1),
                    "indent_values": indentation_values
                } for value in obj),
                "indent_braces": indentation_braces
            }
        else:
            return "\'%(value)s\'" % {"value": str(obj)}

    dict_text = _nested(dictionary)
    return dict_text

Ahora, si tenemos un diccionario como este:

some_dict = {'default': {'ENGINE': [1, 2, 3, {'some_key': {'some_other_key': 'some_value'}}], 'NAME': 'some_db_name', 'PORT': '', 'HOST': 'localhost', 'USER': 'some_user_name', 'PASSWORD': 'some_password', 'OPTIONS': {'init_command': 'SET foreign_key_checks = 0;'}}}

Y nosotros hacemos:

print(_pretty_write_dict(some_dict))

Obtenemos:

{
    'default': {
        'ENGINE': [
            '1',
            '2',
            '3',
            {
                'some_key': {
                    'some_other_key': 'some_value',
                },
            },
        ],
        'NAME': 'some_db_name',
        'OPTIONS': {
            'init_command': 'SET foreign_key_checks = 0;',
        },
        'HOST': 'localhost',
        'USER': 'some_user_name',
        'PASSWORD': 'some_password',
        'PORT': '',
    },
}
Edgardo Obregón
fuente