Un moyen d'imprimer correctement les dictionnaires commandés?

j'aime le module pprint en Python. Je l'utilise beaucoup pour tester et déboguer. J'utilise souvent l'option width pour m'assurer que la sortie s'adapte bien dans ma fenêtre de terminal.

il a bien fonctionné jusqu'à ce qu'ils ont ajouté le nouveau type de dictionnaire ordonné en python 2.7 (une autre caractéristique cool que j'aime vraiment). Si j'essaie d'imprimer un dictionnaire commandé, ça ne se voit pas bien. Au lieu d'avoir chaque paire clé-valeur, sur sa propre ligne, tout s'affiche sur une longue ligne, qui s'enroule plusieurs fois et est difficile à lire.

est-ce que quelqu'un ici a un moyen de le faire imprimer correctement, comme les vieux dictionnaires non ordonnés? Je pourrais probablement trouver quelque chose, peut-être en utilisant le PrettyPrinter.méthode de format, si je passe assez de temps, mais je me demande si quelqu'un ici sait déjà d'une solution.

mise à jour: j'ai déposé un rapport de bogue pour cela. Vous pouvez le voir à http://bugs.python.org/issue10592 .

84
demandé sur martineau 2010-11-29 08:27:27

12 réponses

comme solution temporaire, vous pouvez essayer le dumping au format JSON. Vous perdez quelques informations de type, mais il semble agréable et garde l'ordre.

import json

pprint(data, indent=4)
# ^ugly

print(json.dumps(data, indent=4))
# ^nice
113
répondu webwurst 2014-04-09 12:09:07

ce qui suit fonctionnera si l'ordre de votre OrderedDict est un tri alpha, puisque pprint triera un dict avant impression.

pprint(dict(o.items()))
14
répondu kzh 2010-11-29 05:51:55

Voici une autre réponse qui fonctionne en outrepassant et en utilisant la fonction stock pprint() en interne. Contrairement à mon plus tôt un il will poignée OrderedDict l 'intérieur d'un autre conteneur comme un list et devrait également être en mesure de gérer tous les mots clés facultatifs arguments donnés - cependant, il n'a pas le même degré de contrôle sur la sortie que l'autre permis.

rediriger la sortie de la fonction stock dans un tampon temporaire et ensuite le mot l'enveloppe avant de l'envoyer sur le flux de sortie. Alors que la sortie finale produite n'est pas exceptionnellement jolie, elle est décente et peut être "assez bonne" à utiliser comme solution de contournement.

mise à Jour 2.0

simplifié en utilisant la bibliothèque standard textwrap module, et modifié pour fonctionner dans les deux Python 2 et 3.

from collections import OrderedDict
try:
    from cStringIO import StringIO
except ImportError:  # Python 3
    from io import StringIO
from pprint import pprint as pp_pprint
import sys
import textwrap

def pprint(object, **kwrds):
    try:
        width = kwrds['width']
    except KeyError: # unlimited, use stock function
        pp_pprint(object, **kwrds)
        return
    buffer = StringIO()
    stream = kwrds.get('stream', sys.stdout)
    kwrds.update({'stream': buffer})
    pp_pprint(object, **kwrds)
    words = buffer.getvalue().split()
    buffer.close()

    # word wrap output onto multiple lines <= width characters
    try:
        print >> stream, textwrap.fill(' '.join(words), width=width)
    except TypeError:  # Python 3
        print(textwrap.fill(' '.join(words), width=width), file=stream)

d = dict((('john',1), ('paul',2), ('mary',3)))
od = OrderedDict((('john',1), ('paul',2), ('mary',3)))
lod = [OrderedDict((('john',1), ('paul',2), ('mary',3))),
       OrderedDict((('moe',1), ('curly',2), ('larry',3))),
       OrderedDict((('weapons',1), ('mass',2), ('destruction',3)))]

Sortie de l'échantillon:

pprint(d, width=40)

{'john': 1, 'mary': 3, 'paul': 2}

pprint(od, width=40)

" OrderedDict([('john', 1), ('paul', 2),

    ('mary', 3)])

pprint(lod, width=40)

" [OrderedDict([('john', 1), ('paul', 2),

    ('mary', 3)]), OrderedDict([('moe', 1),

    ('curly', 2), ('larry', 3)]),

    OrderedDict([('weapons', 1), ('mass',

    2), ('destruction', 3)])]

8
répondu martineau 2017-05-23 12:34:44

pour imprimer un dict commandé, p.ex.

from collections import OrderedDict

d=OrderedDict([
    ('a', OrderedDict([
        ('a1',1),
        ('a2','sss')
    ])),
    ('b', OrderedDict([
        ('b1', OrderedDict([
            ('bb1',1),
            ('bb2',4.5)])),
        ('b2',4.5)
    ])),
])

je ne

def dict_or_OrdDict_to_formatted_str(OD, mode='dict', s="", indent=' '*4, level=0):
    def is_number(s):
        try:
            float(s)
            return True
        except ValueError:
            return False
    def fstr(s):
        return s if is_number(s) else '"%s"'%s
    if mode != 'dict':
        kv_tpl = '("%s", %s)'
        ST = 'OrderedDict([\n'; END = '])'
    else:
        kv_tpl = '"%s": %s'
        ST = '{\n'; END = '}'
    for i,k in enumerate(OD.keys()):
        if type(OD[k]) in [dict, OrderedDict]:
            level += 1
            s += (level-1)*indent+kv_tpl%(k,ST+dict_or_OrdDict_to_formatted_str(OD[k], mode=mode, indent=indent, level=level)+(level-1)*indent+END)
            level -= 1
        else:
            s += level*indent+kv_tpl%(k,fstr(OD[k]))
        if i!=len(OD)-1:
            s += ","
        s += "\n"
    return s

print dict_or_OrdDict_to_formatted_str(d)

qui donne

"a": {
    "a1": 1,
    "a2": "sss"
},
"b": {
    "b1": {
        "bb1": 1,
        "bb2": 4.5
    },
    "b2": 4.5
}

ou

print dict_or_OrdDict_to_formatted_str(d, mode='OD')

qui donne

("a", OrderedDict([
    ("a1", 1),
    ("a2", "sss")
])),
("b", OrderedDict([
    ("b1", OrderedDict([
        ("bb1", 1),
        ("bb2", 4.5)
    ])),
    ("b2", 4.5)
]))
7
répondu Ilya Prokin 2015-03-05 19:46:33

Voici une façon de pirater l'implémentation de pprint . pprint trie les clés avant l'impression, donc pour préserver l'ordre, nous devons juste faire le tri des clés comme nous le voulons.

notez que cela a un impact sur la fonction items() . Ainsi, vous pourriez vouloir préserver et restaurer les fonctions overridden après avoir fait l'empreinte.

from collections import OrderedDict
import pprint

class ItemKey(object):
  def __init__(self, name, position):
    self.name = name
    self.position = position
  def __cmp__(self, b):
    assert isinstance(b, ItemKey)
    return cmp(self.position, b.position)
  def __repr__(self):
    return repr(self.name)

OrderedDict.items = lambda self: [
    (ItemKey(name, i), value)
    for i, (name, value) in enumerate(self.iteritems())]
OrderedDict.__repr__ = dict.__repr__

a = OrderedDict()
a[4] = '4'
a[1] = '1'
a[2] = '2'
print pprint.pformat(a) # {4: '4', 1: '1', 2: '2'}
4
répondu rumpel 2015-08-24 17:26:18

C'est assez brut, mais j'avais juste besoin d'un moyen de visualiser une structure de données composée de toutes les applications arbitraires et Iterables et c'est ce que j'ai trouvé avant d'abandonner. Il est récursif,donc il tombera à travers des structures imbriquées et des listes très bien. J'ai utilisé la cartographie et les classes de base abstraites itérables des collections pour gérer à peu près n'importe quoi.

je visais une sortie proche de celle de yaml avec du code Python concis, mais je n'ai pas tout à fait réussi.

def format_structure(d, level=0):
    x = ""
    if isinstance(d, Mapping):
        lenk = max(map(lambda x: len(str(x)), d.keys()))
        for k, v in d.items():
            key_text = "\n" + " "*level + " "*(lenk - len(str(k))) + str(k)
            x += key_text + ": " + format_structure(v, level=level+lenk)
    elif isinstance(d, Iterable) and not isinstance(d, basestring):
        for e in d:
            x += "\n" + " "*level + "- " + format_structure(e, level=level+4)
    else:
        x = str(d)
    return x

et certaines données d'essai en utilisant OrderedDict et des listes de OrderedDicts... (sheesh Python a vraiment besoin d'une ordonnance littéraire...)

d = OrderedDict([("main",
                  OrderedDict([("window",
                                OrderedDict([("size", [500, 500]),
                                             ("position", [100, 900])])),
                               ("splash_enabled", True),
                               ("theme", "Dark")])),
                 ("updates",
                  OrderedDict([("automatic", True),
                               ("servers",
                                [OrderedDict([("url", "http://server1.com"),
                                              ("name", "Stable")]),
                                 OrderedDict([("url", "http://server2.com"),
                                              ("name", "Beta")]),
                                 OrderedDict([("url", "http://server3.com"),
                                              ("name", "Dev")])]),
                               ("prompt_restart", True)])),
                 ("logging",
                  OrderedDict([("enabled", True),
                               ("rotate", True)]))])

print format_structure(d)

donne la production suivante:

   main: 
               window: 
                         size: 
                             - 500
                             - 500
                     position: 
                             - 100
                             - 900
       splash_enabled: True
                theme: Dark
updates: 
            automatic: True
              servers: 
                     - 
                          url: http://server1.com
                         name: Stable
                     - 
                          url: http://server2.com
                         name: Beta
                     - 
                          url: http://server3.com
                         name: Dev
       prompt_restart: True
logging: 
       enabled: True
        rotate: True

j'ai eu quelques pensées le long de la façon d'utiliser str.format () pour un meilleur alignement, mais je n'avais pas envie d'y creuser. Vous aurez besoin de spécifier dynamiquement les largeurs de champ en fonction du type d'alignement que vous voulez, serait soit délicat ou encombrant.

quoi qu'il en soit, cela me montre mes données de manière hiérarchique lisible, de sorte que cela fonctionne pour moi!

2
répondu flutefreak7 2014-02-15 07:54:00
def pprint_od(od):
    print "{"
    for key in od:
        print "%s:%s,\n" % (key, od[key]) # Fixed syntax
    print "}"

vous Y allez ^^

for item in li:
    pprint_od(item)

ou

(pprint_od(item) for item in li)
2
répondu Jakob Bowyer 2015-11-02 23:41:57

la méthode pprint() ne fait qu'invoquer la méthode __repr__() des choses qu'elle contient, et OrderedDict ne semble pas faire grand chose dans sa méthode (ou n'en a pas une ou quelque chose).

Voici une solution bon marché qui devrait fonctionner si vous ne vous souciez pas que la commande soit VISIBLE dans la sortie de PPRINT , qui peut être un grand si:

class PrintableOrderedDict(OrderedDict):
    def __repr__(self):
        return dict.__repr__(self)

en fait, je suis surpris que l'ordre ne soit pas préservé... ah bien.

1
répondu Bill M. 2012-10-26 21:08:05

vous pourriez redéfinir pprint() et intercepter les appels pour OrderedDict 's. Voici une illustration simple. Comme écrit, le OrderedDict outrepasse le code stream , indent , width , ou depth mots-clés qui peuvent avoir été passés, mais pourraient être améliorés pour les mettre en œuvre. Malheureusement, cette technique ne les manipule pas à l'intérieur d'un autre conteneur, comme un list de OrderDict 's

from collections import OrderedDict
from pprint import pprint as pp_pprint

def pprint(obj, *args, **kwrds):
    if not isinstance(obj, OrderedDict):
        # use stock function
        return pp_pprint(obj, *args, **kwrds)
    else:
        # very simple sample custom implementation...
        print "{"
        for key in obj:
            print "    %r:%r" % (key, obj[key])
        print "}"

l = [10, 2, 4]
d = dict((('john',1), ('paul',2), ('mary',3)))
od = OrderedDict((('john',1), ('paul',2), ('mary',3)))
pprint(l, width=4)
# [10,
#  2,
#  4]
pprint(d)
# {'john': 1, 'mary': 3, 'paul': 2}

pprint(od)
# {
#     'john':1
#     'paul':2
#     'mary':3
# }
0
répondu martineau 2010-11-29 10:50:30

si les articles du dictionnaire sont tous d'un type, vous pouvez utiliser l'étonnante bibliothèque de traitement de données pandas :

>>> import pandas as pd
>>> x = {'foo':1, 'bar':2}
>>> pd.Series(x)
bar    2
foo    1
dtype: int64

ou

>>> import pandas as pd
>>> x = {'foo':'bar', 'baz':'bam'}
>>> pd.Series(x)
baz    bam
foo    bar
dtype: object
0
répondu LondonRob 2014-01-25 16:31:02

vous pouvez également utiliser cette simplification de la kzh réponse:

pprint(data.items(), indent=4)

il préserve l'ordre et produira presque le même que le webwurst réponse ( impression par JSON dump ).

0
répondu Albert Alomar 2016-12-09 11:11:14

Voici ma démarche assez de pression pour un OrderedDict

from collections import OrderedDict
import json
d = OrderedDict()
d['duck'] = 'alive'
d['parrot'] = 'dead'
d['penguin'] = 'exploded'
d['Falcon'] = 'discharged'
print d
print json.dumps(d,indent=4)

OutPut:

OrderedDict([('duck', 'alive'), ('parrot', 'dead'), ('penguin', 'exploded'), ('Falcon', 'discharged')])

{
    "duck": "alive",
    "parrot": "dead",
    "penguin": "exploded",
    "Falcon": "discharged"
}

si vous voulez pretty print dictionary avec des clés dans l'ordre trié

print json.dumps(indent=4,sort_keys=True)
{
    "Falcon": "discharged",
    "duck": "alive",
    "parrot": "dead",
    "penguin": "exploded"
}
0
répondu CHINTAN VADGAMA 2018-08-10 20:25:05