15 votes

Puis-je éviter la sortie d'un dictionnaire trié après avoir utilisé pprint.pprint, en Python ?

Le code est :

from pprint import pprint
d = {"b" : "Maria", "c" : "Helen", "a" : "George"}
pprint(d, width = 1)

La sortie est :

{'a': 'George',
'b': 'Maria',
'c': 'Helen'}

Mais, la sortie souhaitée est :

{'b': 'Maria',
'c': 'Helen',
'a': 'George'}

Cela peut-il être fait avec pprint ou existe-t-il un autre moyen ?

20voto

Olivier Melançon Points 15762

Quant à Python 3.7+, dict préserve l'ordre d'insertion. Pour toute version antérieure, vous devrez utiliser un fichier OrderedDict pour garder les clés en ordre.

Bien que, du point de vue doc sur pprint :

Les dictionnaires sont triés par clé avant le calcul de l'affichage.

Cela signifie que pprint brisera l'ordre que vous souhaitez malgré tout.

Utilice json.dumps

Bien qu'il soit possible de sous-classer pprint.PrettyPrinter pour ne pas trier les clés avant l'affichage, c'est fastidieux et une bonne alternative est d'utiliser la fonction json.dumps pour imprimer vos données.

Code

import json
from collections import OrderedDict

# For Python 3.6 and prior, use an OrderedDict
d = OrderedDict(b="Maria", c="Helen", a="George")

print(json.dumps(d, indent=1))

Sortie

{
 "b": "Maria",
 "c": "Helen",
 "a": "George"
}

4voto

blhsing Points 57682

Si vous lisez la source de pprint.py vous trouverez que dans PrettyPrinter._pprint_dict() la méthode responsable du formatage des dicts :

def _pprint_dict(self, object, stream, indent, allowance, context, level):
    write = stream.write
    write('{')
    if self._indent_per_level > 1:
        write((self._indent_per_level - 1) * ' ')
    length = len(object)
    if length:
        items = sorted(object.items(), key=_safe_tuple)
        self._format_dict_items(items, stream, indent, allowance + 1,
                                context, level)
    write('}')

_dispatch[dict.__repr__] = _pprint_dict

Il y a cette ligne items = sorted(object.items(), key=_safe_tuple) Vous devrez l'ignorer vous-même en faisant un copier-coller et en supprimant la ligne en question dans votre propre script :

import pprint as pp
def _pprint_dict(self, object, stream, indent, allowance, context, level):
    write = stream.write
    write('{')
    if self._indent_per_level > 1:
        write((self._indent_per_level - 1) * ' ')
    length = len(object)
    if length:
        self._format_dict_items(object.items(), stream, indent, allowance + 1,
                                context, level)
    write('}')
pp.PrettyPrinter._dispatch[dict.__repr__] = _pprint_dict

de sorte que :

pp.pprint({"b" : "Maria", "c" : "Helen", "a" : "George"}, width=1)

s'affichera (en Python 3.6+) :

{'b': 'Maria',
 'c': 'Helen',
 'a': 'George'}

3voto

blhsing Points 57682

Une solution plus générique consiste à utiliser unittest.mock.patch pour remplacer la fonction intégrée sorted avec une fonction qui ne fait rien d'autre que de retourner le premier argument donné :

import pprint
from unittest.mock import patch

def unsorted_pprint(*args, **kwargs):
    with patch('builtins.sorted', new=lambda l, **_: l):
        orig_pprint(*args, **kwargs)

orig_pprint = pprint.pprint
pprint.pprint = unsorted_pprint

de sorte que :

pprint.pprint({"b" : "Maria", "c" : "Helen", "a" : "George"})

sorties :

{'b': 'Maria', 'c': 'Helen', 'a': 'George'}

2voto

argo Points 2848

Vous devriez utiliser OrderedDict de la bibliothèque collections de python pour garder l'ordre constant.

from collections import OrderedDict
from pprint import pprint
d = OrderedDict({"b" : "Maria", "c" : "Helen", "a" : "George"})
pprint(d, width = 1)

UPDATE :

Comme la sortie est importante, vous pouvez utiliser le code suivant, c'est un hack mais vous créez une fonction pour implémenter cette fonctionnalité :

from collections import OrderedDict
d = OrderedDict({"b" : "Maria", "c" : "Helen", "a" : "George"})
print('{', end='')
total_len = len(d)
current_index = 1
for key, value in d.items():
    print('\''+key+'\': \'' + value+ '\'', end='')
    if current_index<total_len:
        print(',')
    else:
        print('}')
    current_index += 1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X