dernière modification : 2023

JSON et Python

1. Le module JSON

Il permet d’importer et d’exporter simplement du JSON. Exemple :

import json

mydict = {
    "jours_ouvré": [ "lun", "ma", "me", "je", "ve"]
    , "mois_été": [ "jun", "jui", "aug", "sep" ]
    , "solstices":
      [
        { "day": 21 , "month": "dec" }
        , { "day": 21 , "month": "jun" }
    ]
}

print(json.dumps(mydict))

donne :

{"jours_ouvr\u00e9": ["lun", "ma", "me", "je", "ve"], "mois_\u00e9t\u00e9": ["jun", "jui", "aug", "sep"], "solstices": [{"day": 21, "month": "dec"}, {"day": 21, "month": "jun"}]}

et inversement :

import json

s = '{"jours_ouvrés": ["lun", "ma", "me", "je", "ve"], "mois_été": ["jun", "jui", "aug", "sep"], "solstices": [{"day": 21, "month": "dec"}, {"day": 21, "month": "jun"}]}'
var = json.loads(s)

print(type(var))
print(var["mois_été"])

donne :

<class 'dict'>
['jun', 'jui', 'aug', 'sep']

2. Sérialisation

Sérialiser, c’est convertir une structure de données en un flux linéaire d’information, qui doit permettre de la recréer dans un autre contexte (c’est mettre à plat une structure de données potentiellement multi-dimentionnelle). C’est par exemple générer une représentation complète et non ambigüe d’une structure de données sous forme d’une chaine de caractères, qui peut alors être sauvegardée sur un support externe ou envoyée sur un réseau, et pourra être relue par la suite pour reformer l’objet en mémoire.

JSON fait partie des format couramment utilisé pour sérialiser.

2.1. Méthode __repr__()

La méthode __repr__ est censée renvoyer une représentation de l’objet, qui doit permettre de le recréer dans un autre contexte. Concrètement, c’est une fonction qui renvoie une string caractérisant l’état de l’objet.

Cette méthode __repr__ existe par défaut, car elle est utilisée en interne par Python, mais peut être personnalisée.

2.2. Exemples

Lorsque la structure est simple, la sérialisation est triviale :

class Complex:
  def __init__(self,x,y):
    self.x = x
    self.y = y
  def __repr__(self):
    return '{ "Complex": { "x": ' + f"{self.x}" + ', "y": ' + f"{self.y}" + ' } }'

if __name__=="__main__":
  z = Complex(1,2)
  print(repr(z))          # { "Complex": { "x": 1, "y": 2 } }

Lorsque la structure de données est multi-dimentionnelle, l’opération peut s’avérer difficile :

class L:
  def __init__(self,l):
    self.l1 = self.l2 = l

if __name__=="__main__":
  l = L([1,2,3])

l se visualise comme :

serial1

et il est clair que { "l1": [1,2,3], "l2": [1,2,3] }} n’est pas une bonne sérialisation pour l, car elle représente :

serial2

2.3. Persistance

Un objet est persistant si sa durée de vie dépasse celle du programme qui le crée. Pour qu’un objet soit persistant, il suffit qu’il sache sauvegarder son état sur un support externe (par sérialisation) puis qu’il sache se restaurer à partir de cette sauvegarde.

Un programme manipulant des objets persistants peut donc commencer un calcul et s’interrompre avant d’avoir terminé (après avoir enregistrer son environnement), puis plus tard, initier une nouvelle exécution et reprendre le calcul là où il en était.

Les objets issus d’une base de données sont naturellement persistants. Ceux qui savent se sérialiser/désérialiser aussi.