web-dev-qa-db-fra.com

Comment imprimer des dictionnaires imbriqués?

Comment puis-je imprimer un dictionnaire avec une profondeur de ~ 4 en Python? J'ai essayé de jolies impressions avec pprint(), mais cela n'a pas fonctionné:

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

Je veux simplement une indentation ("\t") pour chaque imbrication, afin d'obtenir quelque chose comme ceci:

key1
    value1
    value2
    key2
       value1
       value2

etc. 

Comment puis-je faire ceci?

198
user248237dfsf

Je ne sais pas à quoi ressemble exactement le formatage, mais vous pourriez commencer par une fonction comme celle-ci:

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

( pour l'utilisateur python 2: importer la fonction d'impression de __future__ )

107
sth

Ma première pensée a été que le sérialiseur JSON est probablement assez bon pour les dictionnaires imbriqués, alors je tricherais et utiliserais ça:

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

Vous pouvez essayer YAML via PyYAML . Sa sortie peut être ajustée. Je suggère de commencer par ce qui suit:

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

Le résultat est très lisible; il peut également être analysé dans Python si nécessaire.

Modifier:

Exemple:

>>> 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
43
Andy Mikhaylenko

En ce qui concerne ce qui a été fait, je ne vois pas de jolie imprimante qui imite au moins la sortie de l'interpréteur Python avec un formatage très simple, alors voici le mien:

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)

Pour l'initialiser:

pretty = Formatter()

Il peut prendre en charge l’ajout de formateurs pour des types définis. Vous devez simplement créer une fonction semblable à celle-ci et la lier au type souhaité avec 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)

Pour des raisons historiques, je conserve la jolie imprimante précédente qui était une fonction au lieu d'une classe, mais elles peuvent toutes deux être utilisées de la même manière, la version de la classe autorisant simplement beaucoup plus:

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)

Pour l'utiliser :

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

Par rapport aux autres versions:

  • Cette solution cherche directement le type d'objet, vous pouvez donc presque tout imprimer, pas seulement lister ou dicter.
  • N'a pas de dépendance.
  • Tout est mis dans une ficelle pour que vous puissiez en faire ce que vous voulez.
  • La classe et la fonction ont été testées et fonctionnent avec Python 2.7 et 3.4.
  • Vous pouvez avoir tous les types d'objets à l'intérieur. Il s'agit de leurs représentations et non de leur contenu placé dans le résultat (chaîne a donc des guillemets, les chaînes Unicode sont entièrement représentées ...).
  • Avec la version de la classe, vous pouvez ajouter une mise en forme pour chaque type d'objet souhaité ou les modifier pour ceux déjà définis.
  • la clé peut être de tout type valide.
  • Les caractères de retrait et Newline peuvent être modifiés pour tout ce que nous voulons.
  • Dict, List et Tuples sont joliment imprimés.
30
y.petremann

Une autre option avec 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)

Sortie:

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

J'ai pris la réponse de sth et l'ai légèrement modifiée pour répondre à mes besoins de dictionnaires et de listes imbriquées:

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

Ce qui me donne alors une sortie comme:

>>> 
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
                                            ...
3
Jamie Ivanov

Comme d'autres l'ont écrit, vous pouvez utiliser récursivité/dfs pour imprimer les données de dictionnaire imbriquées et les appeler récursivement s'il s'agit d'un dictionnaire; sinon, imprimez les données.

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

pout peut très bien imprimer tout ce que vous lui lancez, par exemple (emprunter data d'une autre réponse):

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

entraînerait une sortie imprimée à l’écran comme:

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

ou vous pouvez renvoyer la sortie chaîne formatée de votre objet:

v = pout.s(data)

Son principal cas d'utilisation est le débogage afin d'éviter toute surcharge d'instances d'objet et de gérer la sortie unicode comme vous le souhaiteriez, fonctionne en python 2.7 et 3.

Disclosure: Je suis l'auteur et le responsable de la moue.

1
Jaymon
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
Bob Lockwood

Sth, je coule c'est joli;)

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
VindeX

J'ai écrit ce code simple pour imprimer la structure générale d'un objet 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 + ']'

le résultat pour les données suivantes

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)

est très compact et ressemble à ceci:

{
  function:
  Tuple:
  list:
    [
      ...
    ]
  dict:
    {
      a:
      2:
    }
  unicode:
  ('Tuple', 'key'):
}
1
Abtin Rasoulian

de cette façon, vous pouvez l’imprimer de façon jolie, par exemple le nom de votre dictionnaire est yasin

import json

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

De ce lien :

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
user2757572

Utilisez cette fonction:

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

Appelez ça comme ça:

pretty_dict(mydict)
0
fiftytwocards

Voici quelque chose qui imprimera toute sorte de dictionnaire imbriqué, tout en gardant une trace des dictionnaires "parents" tout au long du chemin. 

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)

C’est un bon point de départ pour imprimer selon différents formats, comme celui spécifié dans OP. Tout ce que vous avez vraiment besoin de faire est d’effectuer des opérations autour des blocs Print. Notez qu'il semble voir si la valeur est 'OrderedDict ()'. Selon que vous utilisiez quelque chose de Types de données de conteneur Collections , vous devez créer ce type de sécurité intégrée afin que le bloc Elif ne le considère pas comme un dictionnaire supplémentaire en raison de son nom. A partir de maintenant, un exemple de dictionnaire comme 

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

imprimera

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

~ modifier le code pour l'adapter au format de la question ~

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

En utilisant le même exemple de code, il imprimera ce qui suit: 

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

Ce n'est pas exactement ce qui est demandé dans OP. La différence est qu'un parent ^ n est toujours imprimé, au lieu d'être absent et remplacé par un espace blanc. Pour obtenir le format OP, vous devez procéder comme suit: comparez de manière itérative dicList avec le lastDict. Vous pouvez le faire en créant un nouveau dictionnaire et en y copiant le contenu de dicList, en vérifiant si i dans le dictionnaire copié est identique à i dans lastDict et, le cas échéant, - écrire des espaces à cette position i en utilisant la fonction multiplicateur de chaîne.

0
gavin

Je reviens à cette question après avoir pris la réponse de sth et apporté une modification petite mais très utile. Cette fonction imprime toutes les clés de l’arbre JSON ainsi que la taille des noeuds feuille de cet arbre.

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

C'est vraiment agréable quand vous avez de gros objets JSON et que vous voulez savoir où se trouve la viande. Exemple:

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

Cela vous indiquerait que la plupart des données qui vous intéressent se trouvent probablement dans JSON_object['key1']['key2']['value2'] car la longueur de cette valeur sous forme de chaîne est très grande.

0
Ulf Aslak