Ok, je peux donc utiliser un OrderedDict dans json.dump
. C'est-à-dire qu'un OrderedDict peut être utilisé comme une entrée pour JSON.
Mais peut-il être utilisé comme une sortie? Si c'est le cas, comment? Dans mon cas, je voudrais load
dans un OrderedDict afin de pouvoir conserver l'ordre des clés dans le fichier.
Si non, existe-t-il une solution de contournement?
Oui, vous pouvez. En spécifiant l'argument object_pairs_hook
à JSONDecoder . En fait, ceci est l'exemple exact donné dans la documentation.
>>> json.JSONDecoder(object_pairs_hook=collections.OrderedDict).decode('{"foo":1, "bar": 2}')
OrderedDict([('foo', 1), ('bar', 2)])
>>>
Vous pouvez transmettre ce paramètre à json.loads
(si vous n'avez pas besoin d'une instance de Decoder à d'autres fins) comme ceci:
>>> import json
>>> from collections import OrderedDict
>>> data = json.loads('{"foo":1, "bar": 2}', object_pairs_hook=OrderedDict)
>>> print json.dumps(data, indent=4)
{
"foo": 1,
"bar": 2
}
>>>
Utiliser json.load
se fait de la même manière:
>>> data = json.load(open('config.json'), object_pairs_hook=OrderedDict)
Version simple pour Python 2.7+
my_ordered_dict = json.loads(json_str, object_pairs_hook=collections.OrderedDict)
Ou pour Python 2.4 à 2.6
import simplejson as json
import ordereddict
my_ordered_dict = json.loads(json_str, object_pairs_hook=ordereddict.OrderedDict)
Quelques bonnes nouvelles! Depuis la version 3.6, l’implémentation cPython a conservé l’ordre d’insertion des dictionnaires ( https://mail.python.org/pipermail/python-dev/2016-September/146327.html ). Cela signifie que la bibliothèque json est maintenant en ordre conservant par défaut. Observez la différence de comportement entre python 3.5 et 3.6. Le code:
import json
data = json.loads('{"foo":1, "bar":2, "fiddle":{"bar":2, "foo":1}}')
print(json.dumps(data, indent=4))
Dans py3.5, l'ordre résultant est indéfini:
{
"fiddle": {
"bar": 2,
"foo": 1
},
"bar": 2,
"foo": 1
}
Dans l'implémentation cPython de python 3.6:
{
"foo": 1,
"bar": 2,
"fiddle": {
"bar": 2,
"foo": 1
}
}
La très bonne nouvelle est que cela est devenu une spécification de langage à partir de python 3.7 (par opposition à un détail d'implémentation de cPython 3.6+): https://mail.python.org/pipermail /python-dev/2017-december/151283.html
La réponse à votre question devient alors la suivante: effectuez une mise à niveau vers python 3.6! :)
Vous pouvez toujours écrire la liste des clés en plus de décharger le dict, puis reconstruire la OrderedDict
en parcourant la liste?
Outre le vidage de la liste de clés ordonnée à côté du dictionnaire, une autre solution peu évoluée, qui présente l'avantage d'être explicite, consiste à vider la liste (ordonnée) de paires clé-valeur ordered_dict.items()
; le chargement est une simple OrderedDict(<list of key-value pairs>)
. Cela gère un dictionnaire commandé malgré le fait que JSON n’a pas ce concept (les dictionnaires JSON n’ont pas d’ordre).
Il est en effet agréable de tirer parti du fait que json
vide le OrderedDict dans le bon ordre. Cependant, il est en général inutilement lourd et pas nécessairement significatif de devoir lire tous dictionnaires JSON en tant que OrderedDict (via l'argument object_pairs_hook
), donc une conversion explicite de niquement les dictionnaires à commander ont également un sens.
La commande load normalement utilisée fonctionnera si vous spécifiez le paramètre object_pairs_hook:
import json
from collections import OrderedDict
with open('foo.json', 'r') as fp:
metrics_types = json.load(fp, object_pairs_hook=OrderedDict)