Cours de Python / Lire, écrire et valider des données JSON
JSON, pour JavaScript Object Notation, est un format texte d’échange de données structurées. Dans le module Python json, load et dump travaillent avec un fichier, tandis que loads et dumps travaillent avec du texte en mémoire ; JSON ne conserve pas tous les types d’objets Python à l’identique.
Relier les valeurs JSON aux types Python
| Valeur JSON | Valeur Python habituelle |
|---|---|
| object | dict |
| array | list |
| string | str |
| Nombre entier ou décimal | int ou float selon sa représentation |
| true, false, null | True, False, None |
Les chaînes et les clés d’un objet JSON utilisent des guillemets doubles. Les apostrophes d’un littéral Python, les commentaires et les virgules finales ne sont pas des ajouts arbitrairement permis en JSON. Une chaîne contenant un dictionnaire Python affiché avec print n’est donc pas nécessairement un document JSON valide.
Un tuple sérialisé comme un tableau JSON revient normalement comme une liste à la relecture. Les dates et les objets Decimal ne sont pas sérialisés par défaut : il faut définir une représentation explicite, par exemple un format de date ou une convention pour les décimaux. La documentation officielle de json décrit les conversions et leurs paramètres.
Enregistrer une dépense Unicode et la relire
Python 3 et sa bibliothèque standard suffisent. Utilisez un dossier d’exercice : le programme remplace expenses-demo.json. Le nom café sert à rendre visible un caractère non ASCII ; KRW reste l’unité de l’exemple, le won sud-coréen.
Enregistrez le bloc complet dans json_demo.py, en UTF-8. Dans un terminal ouvert dans ce dossier avec l’environnement virtuel du projet activé, lancez python json_demo.py. Sur macOS ou Ubuntu hors environnement virtuel, utilisez python3 json_demo.py si votre interpréteur porte ce nom. Évitez le nom de script json.py pour ne pas masquer le module standard.
import json
from pathlib import Path
data = {"currency": "KRW", "expenses": [{"name": "café", "amount": 8000}]}
path = Path("expenses-demo.json")
path.write_text(json.dumps(data, ensure_ascii=False, indent=2, allow_nan=False), encoding="utf-8")
loaded = json.loads(path.read_text(encoding="utf-8"))
amount = loaded["expenses"][0]["amount"]
if type(amount) is not int or amount < 0:
raise ValueError("invalid amount")
print(loaded["expenses"][0]["name"])
print(amount)
Le résultat attendu est :
café
8000
dumps transforme data en texte JSON ; write_text l’enregistre ensuite en UTF-8. read_text relit ce texte et loads reconstruit les données Python. Le contrôle vérifie que le montant est exactement un entier natif non négatif avant d’afficher le nom et 8000. Ouvrez aussi le fichier généré pour vérifier les clés, le tableau expenses et le nom café.
Distinguer analyse syntaxique et validation métier
Un document JSON peut être syntaxiquement correct mais ne pas avoir les clés attendues, contenir un tableau vide ou fournir un montant du mauvais type. L’exemple suppose une structure connue et vérifie seulement son montant ; un importateur général doit aussi contrôler le type de l’objet racine, le tableau expenses, ses éléments et leurs champs avant de les indexer.
type(amount) is int exclut volontairement un booléen : True est une instance d’int en Python, mais ce n’est pas un montant accepté ici. Un test avec isinstance peut convenir si les sous-classes doivent être autorisées ; choisissez selon le contrat. Le test du montant négatif représente ensuite une règle distincte du type.
| Fonction | Entrée et résultat |
|---|---|
load(file) |
Lit un document depuis un objet fichier et renvoie des données Python |
loads(text) |
Analyse le texte JSON fourni |
dump(data, file) |
Écrit le document dans un objet fichier |
dumps(data) |
Renvoie une chaîne de texte JSON |
allow_nan=False rejette NaN et les infinis lors de la sérialisation. Il ne configure pas le décodeur utilisé ensuite : par défaut, Python accepte certains nombres non standard à la lecture. Pour une entrée strictement conforme, définissez séparément une politique pour ces constantes, par exemple via parse_constant, et pour les clés répétées, qui sont remplacées par la dernière valeur avec le comportement habituel. Le contrôle de sortie ne remplace pas la validation d’un fichier extérieur.
Vérifier les caractères, les erreurs et les modifications
ensure_ascii=False conserve les caractères non ASCII sous une forme lisible lorsque leur échappement n’est pas obligatoire. Ce paramètre ne choisit pas l’encodage du fichier : UTF-8 est indiqué séparément dans write_text et read_text. indent=2 ajoute une présentation indentée sans changer la structure des données.
- Changez uniquement 8000 dans data en -1. La sérialisation réussit, mais la validation du montant lève
ValueError: invalid amount, qui signifie « montant invalide ». Restaurez ensuite 8000. - Dans le code Python, remplacez le montant par
Trueavec une majuscule. Le JSON écrit contient alors true, mais la validation rejette le booléen à la relecture. Restaurez l’entier. La forme minuscule true appartient au texte JSON, pas à la syntaxe d’un littéral booléen Python. - Changez seulement ensure_ascii en True. Le fichier représente le é par un échappement Unicode, mais la relecture affiche toujours café et 8000. Rétablissez False et vérifiez le fichier lisible.
Un texte mal formé provoque une JSONDecodeError : corrigez la syntaxe au lieu de remplacer json par eval. Une édition manuelle du fichier d’exercice serait écrasée au prochain lancement complet, puisque le programme commence par le réécrire. Pour éprouver une entrée extérieure, séparez la lecture de la génération du fichier et validez également sa structure.
Une donnée rejetée par la validation peut déjà avoir été écrite par ce programme pédagogique. Si seules des données approuvées doivent être enregistrées dans une application réelle, faites la validation avant l’écriture et définissez une stratégie de remplacement. Les différences entre contenu, encodage et protection de l’original suivent les règles de l’écriture de fichiers texte.




