J'aime le module pprint en Python. Je l'utilise beaucoup pour tester et déboguer. J'utilise fréquemment l'option width pour m'assurer que la sortie s'adapte bien à la fenêtre de mon terminal.
Cela a bien fonctionné jusqu'à ce qu'ils ajoutent le nouveau dictionnaire de type ordonné dans Python 2.7 (une autre fonctionnalité intéressante que j'aime beaucoup). Si j'essaie d'imprimer un dictionnaire en ordre, cela ne se voit pas bien. Au lieu d’avoir chaque paire clé-valeur sur sa propre ligne, le tout apparaît sur une longue ligne, qui est renvoyée à plusieurs reprises et qui est difficile à lire.
Est-ce que quelqu'un ici a un moyen de le faire bien imprimer, comme les vieux dictionnaires non ordonnés? Je pourrais probablement trouver quelque chose, éventuellement en utilisant la méthode PrettyPrinter.format, si je passe suffisamment de temps, mais je me demande si quelqu'un ici connaît déjà une solution.
UPDATE: J'ai déposé un rapport de bogue pour cela. Vous pouvez le voir sur http://bugs.python.org/issue10592 .
En guise de solution de contournement temporaire, vous pouvez essayer le dumping au format JSON . Vous perdez certaines informations de type, mais elles ont l'air bien et conservent la commande.
import json
pprint(data, indent=4)
# ^ugly
print(json.dumps(data, indent=4))
# ^Nice
Ce qui suit fonctionnera si l'ordre de votre OrderedDict est un tri alpha, car pprint triera un dict avant impression.
pprint(dict(o.items()))
Voici une autre réponse qui fonctionne en remplaçant et en utilisant la fonction stock pprint()
en interne. Contrairement à mon précédent il sera gérer OrderedDict
dans un autre conteneur tel qu'un list
et devrait également pouvoir gérer arguments de mot clé facultatifs donnés - toutefois, il n’exerce pas le même degré de contrôle sur la sortie que l’autre.
Il fonctionne en redirigeant la sortie de la fonction stock dans un tampon temporaire, puis Word le retourne avant de l'envoyer au flux de sortie. Bien que la sortie finale produite ne soit pas exceptionnellement jolie, elle est décente et peut être "assez bonne" pour être utilisée comme solution de contournement.
Mise à jour 2.0
Simplifié en utilisant le module standard textwrap
de la bibliothèque standard, et modifié pour fonctionner à la fois dans Python 2 & 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)))]
Exemple de sortie:
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)])]
Pour imprimer un dict ordonné, par exemple.
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 fais
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)
Quels rendements
"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)
]))
Voici un moyen de pirater l’implémentation de pprint
.pprint
pour trier les clés avant l’impression. Pour préserver l’ordre, il suffit donc de trier les clés à la manière souhaitée.
Notez que cela a un impact sur la fonction items()
. Il est donc utile de conserver et de restaurer les fonctions remplacées après l’impression p.
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'}
def pprint_od(od):
print "{"
for key in od:
print "%s:%s,\n" % (key, od[key]) # Fixed syntax
print "}"
Voilà
for item in li:
pprint_od(item)
ou
(pprint_od(item) for item in li)
C'est assez grossier, mais j'avais juste besoin d'un moyen de visualiser une structure de données constituée de mappages et d'itables arbitraires et c'est ce que j'ai proposé avant d'abandonner. C'est récursif, donc il va très bien tomber dans les structures imbriquées et les listes. J'ai utilisé les classes de base abstraites Mapping et Iterable des collections pour gérer à peu près tout.
Je visais presque une sortie similaire à yaml avec un code python concis, mais je n’ai pas réussi à le faire.
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 quelques données de test utilisant OrderedDict et des listes de OrderedDicts ... (sheesh Python a besoin de littéraux de OrderedDict tellement terriblement mauvais ...)
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 le résultat suivant:
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'avais quelques idées sur l'utilisation de str.format () pour un meilleur alignement, mais je n'avais pas envie de creuser. Vous devez spécifier dynamiquement les largeurs de champ en fonction du type d'alignement souhaité, ce qui peut s'avérer délicat ou fastidieux.
Quoi qu'il en soit, cela me montre mes données de manière hiérarchique lisible, alors ça marche pour moi!
La méthode pprint()
appelle simplement la méthode __repr__()
dans laquelle elle se trouve, et OrderedDict
ne semble pas faire grand chose dans sa méthode (ou n'en a pas un ou quelque chose).
Voici une solution peu coûteuse qui devrait fonctionner SI VOUS NE FAITES PAS DE L'ORDRE VISIBLE DANS LA SORTIE DU PPRINT , ce qui peut être un problème si:
class PrintableOrderedDict(OrderedDict):
def __repr__(self):
return dict.__repr__(self)
Je suis en fait surpris que l'ordre ne soit pas préservé ... ah bien.
Si les éléments du dictionnaire sont tous d'un seul 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
Vous pouvez redéfinir pprint()
et intercepter les appels de OrderedDict
. Voici une illustration simple. Tel qu'écrit, le code de substitution OrderedDict
ignore les mots clés stream
, indent
, width
ou depth
facultatifs qui ont peut-être été transmis, mais qui pourraient être améliorés pour les implémenter. Malheureusement, cette technique ne les gère pas dans un autre conteneur, tel que 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
# }
J'ai testé ce hack basé sur le patch de singe sur python3.5 et cela fonctionne:
pprint.PrettyPrinter._dispatch[pprint._collections.OrderedDict.__repr__] = pprint.PrettyPrinter._pprint_dict
def unsorted_pprint(data):
def fake_sort(*args, **kwargs):
return args[0]
orig_sorted = __builtins__.sorted
try:
__builtins__.sorted = fake_sort
pprint.pprint(data)
finally:
__builtins__.sorted = orig_sorted
Vous faites en sorte que pprint
utilise le résumé habituel basé sur dict et que vous désactiviez également le tri pendant la durée de l'appel afin qu'aucune clé ne soit réellement triée pour l'impression.
Voici mon approche de la jolie impression d'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 imprimer un dictionnaire avec les clés dans l’ordre trié
print json.dumps(indent=4,sort_keys=True)
{
"Falcon": "discharged",
"duck": "alive",
"parrot": "dead",
"penguin": "exploded"
}