Des données imbriquées en texte
Le JSON est le format courant des fichiers de configuration et des données échangées entre programmes et API web. Il est fait d'objets {"clé": valeur}, de tableaux [1, 2], de chaînes, de nombres, de true/false et de null. Cela correspond directement à Python : les objets deviennent des dictionnaires, les tableaux des listes, true/false deviennent True/False et null devient None. Contrairement à un tableau CSV, le JSON peut s'imbriquer : un ordre peut contenir une liste d'exécutions, chacune avec ses propres champs.
import json
# Text to Python: loads() ("load string")
text = '{"symbol": "AAPL", "fills": [{"price": 184.25, "qty": 100}], "open": true, "note": null}'
order = json.loads(text)
print(order["fills"][0]["price"]) # 184.25
print(order["open"], order["note"]) # True None
# Python to text: dumps() ("dump string")
print(json.dumps({"symbol": "AAPL", "qty": 200})) # {"symbol": "AAPL", "qty": 200}Fichiers : load et dump
Les versions sans s travaillent sur des fichiers : json.load(file) lit et analyse un fichier ouvert, et json.dump(data, file) l'écrit. Passez indent=2 pour rendre le fichier lisible par des humains et sort_keys=True pour un ordre de clés stable, ce qui garde les différences petites dans le contrôle de version. Ouvrez toujours avec with et encoding="utf-8".
import json
# Save a config, then load it back
config = {"fee": 0.001, "symbols": ["MSFT", "AAPL"], "limits": {"max_qty": 500}}
with open("config.json", "w", encoding="utf-8") as file:
json.dump(config, file, indent=2, sort_keys=True)
with open("config.json", encoding="utf-8") as file:
print(file.read())
# {
# "fee": 0.001,
# "limits": {
# "max_qty": 500
# },
# "symbols": [
# "MSFT",
# "AAPL"
# ]
# }
with open("config.json", encoding="utf-8") as file:
print(json.load(file) == config) # TrueCe qui ne survit pas au voyage
Le JSON n'a que peu de types, donc certaines valeurs Python changent en route. Les tuples reviennent en listes, les clés de dictionnaire reviennent toujours en chaînes ({1: "a"} revient en {"1": "a"}), et les ensembles, dates et objets personnalisés ne peuvent pas du tout être sérialisés (TypeError) tant qu'on ne les convertit pas, par exemple une date avec .isoformat() ou un ensemble avec sorted(...). Rappelez-vous aussi que NaN et l'infini ne sont pas du JSON valide.
import json
from datetime import date
# Tuples become lists, int keys become strings
data = {"pair": (1, 2), 7: "seven"}
print(json.loads(json.dumps(data))) # {'pair': [1, 2], '7': 'seven'}
# A date has to be converted by hand
today = date(2025, 1, 2)
print(json.dumps({"day": today.isoformat()})) # {"day": "2025-01-02"}Entrée invalide
Un texte venu de l'extérieur, comme un message d'une bourse, peut ne pas être du JSON valide. json.loads lève alors json.JSONDecodeError, une sorte de ValueError, et un JSON valide peut quand même manquer de la clé voulue (KeyError) ou avoir une autre forme (TypeError). Entourez l'analyse d'un try/except et décidez ce qu'un message invalide signifie pour votre programme. Le prochain sujet traite des exceptions en détail.
import json
# Bad input raises, so catch it where you parse
def get_price(text):
try:
return json.loads(text)["price"]
except (ValueError, KeyError, TypeError):
return None
print(get_price('{"price": 184.25}')) # 184.25
print(get_price("not json")) # None
print(get_price('{"symbol": "AAPL"}')) # Nonejson.dumps ou json.dump produire le texte, et json.loads ou json.load le lire. Même principe pour fusionner des réglages : copiez avant de modifier, afin qu'une configuration ne déborde pas sur une autre.json.loads(text)/json.dumps(data)travaillent sur des chaînes ;json.load(file)/json.dump(data, file)sur des fichiers.indent=2etsort_keys=Truerendent les fichiers lisibles et stables.- Une entrée invalide lève
ValueError,KeyErrorouTypeError: interceptez ce que vous attendez.
À suivre : les exceptions et la gestion des erreurs, pour que vos programmes échouent clairement et se rétablissent quand il le faut.
Lab : ce qui est noté
- Totaliser les ordres d'un fichier JSON avec
order_total25 pts - Enregistrer des réglages en JSON lisible avec
save_config25 pts - Lire un message de cotation en toute sécurité avec
parse_quote25 pts - Superposer des réglages aux valeurs par défaut avec
merge_configs25 pts