Como imprimir dicionários aninhados?


289

Como posso imprimir um dicionário com profundidade de ~ 4 em Python? Tentei bastante imprimir pprint(), mas não funcionou:

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

Eu simplesmente quero um indentation ( "\t") para cada aninhamento, para obter algo assim:

key1
    value1
    value2
    key2
       value1
       value2

etc.

Como posso fazer isso?


29
O que significa "não funcionou"? Especifique com muita precisão como o pprint "não funcionou".
31510 S.Lott

5
Agora, usei três dessas respostas (cada uma boa em um cenário específico): @ A resposta json de Ken é boa, mas falha às vezes quando o objeto não pode ser json serializável (lança exceção). se a resposta json de @ Ken não funcionar, tente a resposta yaml de Andy e deve funcionar, mas a saída da string é um pouco menos legível por humanos. [resposta do @ sth] é a mais genérica (deve funcionar para qualquer objeto e não usa nenhuma biblioteca).
Trevor Boyd Smith

Respostas:


143

Não sei exatamente como você deseja que a formatação seja exibida, mas você pode começar com uma função 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))

8
Você sabe que a resposta convencional de Ken é muito melhor que isso. O Json já lida com tudo e isso pode gerar erros como: UnicodeEncodeError: o codec 'ascii' não pode codificar o caractere u '\ xf3' na posição 50: ordinal não está no intervalo (128)
wonderwhy

Não posso fazê-lo funcionar com o dict aninhado da minha solução, porque ele me deu um UnicodeEncodeError, também não imprime chave de dict, não entra na lista e nas tuplas e não mantém uma sintaxe válida em python.
y.petremann

Esta resposta funcionou como um encanto para mim, no entanto, postei uma nova pergunta stackoverflow.com/questions/36972225/… que define um limite para quantos valores devem ser impressos.
gsamaras

Muito bom. Se você tem listas aninhadas, como na pergunta do OP, é necessário adicionar um pouco de manipulação para isso. Se você está tendo problemas no Py2, é porque ele não consegue lidar com o Unicode corretamente sem hacks como os __future__que a resposta agora menciona, então você deve empregá-los sempre que necessário (ou atualizar para o 3 já).
sudo

Isso funcionou bem o suficiente para mim: 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 27/04

500

Meu primeiro pensamento foi que o serializador JSON provavelmente é muito bom em dicionários aninhados, então eu trapaceava e usava isso:

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

40
Isso é legal, mas não imprime todos os dicionários corretamente. imprimir json.dumps (myObject .__ dict__, sort_keys = True, travessão = 4) #TypeError: <object em 0x0000000002E6A748> não é JSON serializado
tponthieux

4
Embora isso pareça útil, sua saída não é o que o OP queria.
martineau

2
@martineau: a saída solicitada pelo OP não faz sentido, os dicionários precisam de chaves por valor.
precisa saber é o seguinte

2
@ naught101: Uma impressora bonita pode fazer o que for necessário para produzir a saída desejada.
martineau

22
O json.dumps aceita uma função de conversão como argumento opcional; portanto, com o json.dumps (myObject .__ dict__, sort_keys = True, indent = 4, deault = str) você pode pelo menos usar uma implementação de objetos de repr para imprimir a si mesma e contornar o 'não JSON serializado' TypeError
RFairey

56

Você pode tentar o YAML via PyYAML . Sua saída pode ser ajustada. Eu sugiro começar com o seguinte:

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

O resultado é muito legível; também pode ser analisado de volta para Python, se necessário.

Editar:

Exemplo:

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

1
O uso do yaml é muito interessante porque mantém o tipo de dados acima do formato, a única coisa que posso dizer é que ele não produz uma string python válida, mas quase pode ser convertido novamente em python.
usar o seguinte código

1
yaml não como a versão de Numpy de tipos escalares ... Eu não estava surpreso que é não suporta matrizes numpy, mas eu teria esperado a mesma saída para um floate umnumpy.float64
PhilMacKay

essa abordagem também funcionou para mim usando uma lista de dicionários
Grant Shannon

36

Pelo que foi feito, não vejo nenhuma impressora bonita que imite pelo menos a saída do interpretador python com formatação muito simples, então aqui está a minha:

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 inicializá-lo:

pretty = Formatter()

Ele pode suportar a adição de formatadores para tipos definidos, basta criar uma função para essa como esta e vinculá-la ao tipo que você deseja com 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 razões históricas, mantenho a impressora bonita anterior, que era uma função em vez de uma classe, mas ambas podem ser usadas da mesma maneira, a versão da classe simplesmente permite muito mais:

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 usá-lo :

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

Comparado com outras versões:

  • Esta solução procura diretamente o tipo de objeto, para que você possa praticamente imprimir quase tudo, não apenas listar ou ditar.
  • Não tem nenhuma dependência.
  • Tudo é colocado dentro de uma string, para que você possa fazer o que quiser com ela.
  • A classe e a função foram testadas e funcionam com o Python 2.7 e 3.4.
  • Você pode ter todos os tipos de objetos, essas são suas representações e não o conteúdo que está sendo colocado no resultado (para que as strings tenham aspas, as strings Unicode são totalmente representadas ...).
  • Com a versão da classe, você pode adicionar formatação para cada tipo de objeto desejado ou alterá-lo para os já definidos.
  • A chave pode ser de qualquer tipo válido.
  • Os caracteres de recuo e nova linha podem ser alterados para tudo o que gostaríamos.
  • Dict, List e Tuples são bastante impressas.

2
Definitivamente, essa deve ser a solução aceita - a falta de dependência do JSON é enorme.
13133 Josh

que seria legal se ele poderia fazer objetos, convertendo-os dicts e definindo sua chave para ser o tipo de objeto
Alex Cory

Você pode basicamente substituir o método format_object interna ou externamente para fazer isso.
y.petremann 23/09/16

set_formater - precisa de dois t, este é um erro de digitação, deve ser formatador
Nikolay Prokopyev

32

Dessa forma, você pode imprimi-lo de maneira bonita, por exemplo, o nome do seu dicionário é yasin

import json

print (json.dumps(yasin, indent=2))

5
Isso pressupõe que o conteúdo do dicionário possa ser serializado pelo json, o que não é necessariamente verdadeiro.
SpiXel 07/10/19

8

Outra opção com 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)

Resultado:

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

5

Como outras pessoas postaram, você pode usar recursion / dfs para imprimir os dados do dicionário aninhado e chamar recursivamente se for um dicionário; caso contrário, imprima os dados.

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

5

Uma das maneiras mais pitônicas para isso é usar o módulo pprint já construído .

O argumento necessário para definir a profundidade da impressão é o que você pode esperar depth

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

É isso aí !


4

pout pode imprimir qualquer coisa que você jogue nele, por exemplo (tomando emprestado datade outra resposta):

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

resultaria na saída impressa na tela como:

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

ou você pode retornar a saída da string formatada do seu objeto:

v = pout.s(data)

Seu caso de uso principal é para depuração, para que não ocorra instâncias de objetos ou qualquer coisa e lida com a saída unicode como seria de esperar, funciona no python 2.7 e 3.

divulgação : sou o autor e mantenedor do faneca.


3

Peguei a resposta do sth e a modifiquei um pouco para atender às minhas necessidades de dicionários e listas aninhados:

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

O que me dá uma saída 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
                                            ...

1

Sth, eu afundo isso é 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)))

1
-1: não manipula listvalores que não são dictinstâncias, ou seja, pretty({'key': [1, 2, 3]}, indent=4)==> AttributeError: 'int' object has no attribute 'iteritems'. Também não gosto de teclas maiúsculas.
27513 Martinineau

Sua solução considera que não pode haver um ditado dentro de uma lista dentro do ditado raiz. Também considera que não queremos imprimir uma lista ou uma tupla. Por fim, não use letras maiúsculas em maiúsculas, o resultado para {'a': 0, 'A': 1} não estaria correto.
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)

1

Eu escrevi esse código simples para imprimir a estrutura geral de um objeto json em 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 + ']'

o resultado para os seguintes dados

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)

é muito compacto e tem a seguinte aparência:

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

0

Eu também sou um novato em python, mas tenho trabalhado com dicionários aninhados nas últimas duas semanas e foi isso que eu criei.

Você deve tentar usar uma pilha. Transforme as chaves do dicionário raiz em uma lista de uma lista:

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

Indo na ordem inversa do último para o primeiro, procure cada chave no dicionário para ver se seu valor é (também) um dicionário. Caso contrário, imprima a chave e exclua-a. No entanto, se o valor da chave for um dicionário, imprima a chave e, em seguida, acrescente as chaves desse valor ao final da pilha e comece a processar essa lista da mesma maneira, repetindo recursivamente para cada nova lista de chaves.

Se o valor da segunda chave em cada lista fosse um dicionário, você teria algo assim depois de várias rodadas:

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

A vantagem dessa abordagem é que o recuo é apenas \to dobro do comprimento da pilha:

indent = "\t" * len(stack)

A desvantagem é que, para verificar cada chave, você precisa fazer o hash no sub-dicionário relevante, embora isso possa ser tratado facilmente com uma compreensão de lista e um forloop simples :

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

Esteja ciente de que essa abordagem exigirá que você limpe as listas vazias à direita e exclua a última chave em qualquer lista seguida por uma lista vazia (que, é claro, pode criar outra lista vazia e assim por diante).

Existem outras maneiras de implementar essa abordagem, mas espero que isso lhe dê uma idéia básica de como fazê-lo.

EDIT: Se você não quiser passar por tudo isso, o pprintmódulo imprime dicionários aninhados em um bom formato.


0

Aqui está uma função que escrevi com base no comentário do sth. Funciona da mesma forma que json.dumps com recuo, mas estou usando guias em vez de espaço para recuos. No Python 3.2+, você pode especificar que o recuo seja um '\ t' diretamente, mas não no 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"
    }
}

Não posso fazê-lo funcionar com o dict aninhado da minha solução, porque ele me deu um UnicodeEncodeError; também itens e chaves são todos convertidos em strings. E se usarmos números ou tuplas que contenham listas e dictos? Por fim, sua solução leva em consideração que nosso objeto que queremos imprimir deve ser um ditado.
y.petremann

Eu não estava tentando escrever uma função de impressão genérica para um ditado python. Os comentários mais votados já demonstram como imprimir um ditado. Minha contribuição foi escrever uma alternativa ao json.dumps com '\ t' para recuar em vez de guias no python 2.7.
Al Conrad

Concordo com você em escrever uma alternativa ao json.dumps, para mim os mesmos problemas que o json.dumps se aplicam. Além disso, você pode usar um regex simples para alterar o tipo de indentação, tornando seu código mais simples.
usar o seguinte código

0

Aqui está algo que imprimirá qualquer tipo de dicionário aninhado, mantendo o controle dos dicionários "pais" ao longo do caminho.

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)

Esse é um bom ponto de partida para imprimir de acordo com diferentes formatos, como o especificado no OP. Tudo o que você realmente precisa fazer é operar nos blocos de impressão . Observe que parece ver se o valor é 'OrderedDict ()'. Dependendo de você estar usando algo das coleções de tipos de dados Container , você deve fazer esse tipo de proteção contra falhas para que o bloco elif não o veja como um dicionário adicional devido ao seu nome. A partir de agora, um exemplo de dicionário como

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

irá 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']

~ alterando o código para se ajustar ao formato da pergunta ~

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 o mesmo código de exemplo, ele imprimirá o seguinte:

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

Isso não é exatamente o que é solicitado no OP. A diferença é que um pai ^ n ainda é impresso, em vez de estar ausente e substituído por espaço em branco. Para chegar ao formato do OP, você precisará fazer algo como o seguinte: compare iterativamente dicList com o lastDict . Você pode fazer isso criando um novo dicionário e copiando o conteúdo da dicList para ele, verificando se i no dicionário copiado é o mesmo que i no lastDict e - se estiver - escrevendo espaço em branco nesse posição eu uso, usando a função multiplicadora de strings .


0

A partir deste link :

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]
}
'''

0

Acabei de voltar a esta pergunta depois de receber a resposta de sth e fazer uma modificação pequena, mas muito útil. Essa função imprime todas as chaves na árvore JSON , bem como o tamanho dos nós das folhas nessa árvore.

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

É muito bom quando você tem objetos JSON grandes e deseja descobrir onde está a carne. Exemplo :

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

Isso indica que a maioria dos dados importantes provavelmente está dentro, JSON_object['key1']['key2']['value2']porque o comprimento desse valor formatado como uma string é muito grande.


0

Use esta função:

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

Chame assim:

pretty_dict(mydict)

Isso não funciona se os valores forem cadeias de caracteres. Ele imprime cada caractere da string em uma nova linha, mas as teclas parecem funcionar bem.
Anthony

0

Isto é o que eu criei enquanto trabalhava em uma classe que precisava escrever um dicionário em um arquivo .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

Agora, se tivermos um dicionário 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;'}}}

E nós fazemos:

print(_pretty_write_dict(some_dict))

Nós temos:

{
    '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': '',
    },
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.