27. Sérialisation Avancée
pickle,jsonavancé,msgpack,parquet,hdf5,zarr, protobuf,PyYAML,toml, performance, sécurité.
27.1 pickle — sérialisation Python native
import pickle
data = {"nom": "Alice", "scores": [1, 2, 3], "obj": lambda x: x * 2}
# Sérialiser → bytes
octets = pickle.dumps(data)
# Déserialiser
restauré = pickle.loads(octets)
# Fichier
with open("data.pkl", "wb") as f:
pickle.dump(data, f)
with open("data.pkl", "rb") as f:
restauré = pickle.load(f)Protocoles
pickle.dumps(data, protocol=5) # 5 = protocol par défaut (3.8+)
pickle.DEFAULT_PROTOCOL # 5
# Protocoles: 0 (texte), 1-2 (anciens binaires), 3-4 (binaires modernes),
# 5 (3.8+, buffers out-of-band)Pickle et classes personnalisées
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __reduce__(self):
"""Contrôle la sérialisation pickle."""
return (self.__class__, (self.x, self.y))
p = Point(1, 2)
restauré = pickle.loads(pickle.dumps(p))⚠️ Sécurité
Ne jamais dépickler des données non fiables — exécution de code arbitraire.
import pickletools
# Vérifier qu'un pickle est sûr (analyse statique)
with open("data.pkl", "rb") as f:
pickletools.dis(f) # désassembler les opcodes pickleAlternatives sécurisées : json, msgpack, protobuf, pyarrow.serialize (déprécié).
27.2 json avancé
Sérialiseurs personnalisés
import json
from datetime import datetime
from pathlib import Path
import numpy as np
class JSONEncoderCustom(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, Path):
return str(obj)
if isinstance(obj, np.ndarray):
return obj.tolist()
if isinstance(obj, np.integer):
return int(obj)
if isinstance(obj, np.floating):
return float(obj)
return super().default(obj)
with open("data.json", "w") as f:
json.dump({"date": datetime.now(), "path": Path("/tmp")}, f, cls=JSONEncoderCustom)json.dumps formaté
# Compact
json.dumps(data, separators=(",", ":")) # pas d'espaces
# Formaté
json.dumps(data, indent=2, sort_keys=True, ensure_ascii=False)Itération sur grands JSON
import ijson # pip install ijson
with open("énorme.json", "rb") as f:
for item in ijson.items(f, "item"):
traiter(item) # streaming, pas de chargement complet27.3 msgpack — binaire compact et rapide
pip install msgpackimport msgpack
data = {"nom": "Alice", "âge": 30, "scores": [1.0, 2.0, 3.0]}
# Sérialisation
packed = msgpack.packb(data)
print(len(packed)) # plus petit que JSON
# Déserialisation
restauré = msgpack.unpackb(packed)Comparaison taille :
import json, msgpack, pickle
data = {"a": list(range(1000)), "b": {"nested": "data" * 100}}
len(json.dumps(data)) # ~1200 octets
len(msgpack.packb(data)) # ~1000 octets (plus compact)
len(pickle.dumps(data)) # ~2100 octets27.4 parquet — format colonnaire
pip install pyarrow # ou fastparquetimport pandas as pd
import numpy as np
# Création
df = pd.DataFrame({
"a": np.random.rand(1000),
"b": np.random.randint(0, 100, 1000),
"c": ["chat", "chien"] * 500,
})
# Écriture
df.to_parquet("data.parquet")
# Lecture
df = pd.read_parquet("data.parquet")
# Avec pyarrow directement
import pyarrow as pa
import pyarrow.parquet as pq
table = pa.Table.from_pandas(df)
pq.write_table(table, "data.parquet")
table = pq.read_table("data.parquet")Avantages : compression élevée, lecture sélective de colonnes, adapté au ML.
27.5 hdf5 — hiérarchique, scientifique
pip install h5pyimport h5py
import numpy as np
# Écriture
with h5py.File("données.h5", "w") as f:
f.create_dataset("train/images", data=np.random.rand(100, 32, 32, 3))
f.create_dataset("train/labels", data=np.random.randint(0, 10, 100))
# Attributs (métadonnées)
f.attrs["description"] = "Dataset d'entraînement"
f.attrs["version"] = 1
# Groupes hiérarchiques
grp = f.create_group("config")
grp.attrs["learning_rate"] = 0.001
grp.create_dataset("paramètres", data=np.array([1, 2, 3]))
# Lecture
with h5py.File("données.h5", "r") as f:
images = f["train/images"][:] # chargement complet
images = f["train/images"][0:32] # chargement partiel (slicing)
print(f.attrs["description"])Lecture partielle (essentiel pour gros datasets)
with h5py.File("gros.h5", "r") as f:
ds = f["data"]
# On peut slicer sans charger en mémoire
batch = ds[100:200] # ne charge que 100 éléments27.6 zarr — arrays chunkés, cloud-native
pip install zarrimport zarr
import numpy as np
# Stockage local
z = zarr.open_array("data.zarr", mode="w", shape=(1000, 1000), dtype="f4",
chunks=(100, 100))
z[:] = np.random.rand(1000, 1000)
# Lecture
z = zarr.open_array("data.zarr", mode="r")
print(z[0:10, 0:10]) # ne charge que les chunks nécessaires
# Stockage cloud (S3, GCS)
store = zarr.ABSStore("bucket", prefix="data")
z = zarr.open_array(store, mode="r")Avantages : chunked, compression, parallélisable, compatible cloud.
27.7 PyYAML — configuration humaine
pip install pyyaml# config.yaml
model:
name: resnet20
hidden_size: 256
dropout: 0.1
training:
batch_size: 64
learning_rate: 0.001
epochs: 100import yaml
with open("config.yaml") as f:
config = yaml.safe_load(f) # safe_load (pas yaml.load)
print(config["model"]["name"])
print(config["training"]["learning_rate"])27.8 toml — configuration (pyproject.toml)
import tomllib # stdlib 3.11+
with open("config.toml", "rb") as f:
config = tomllib.load(f)
# Avant 3.11 : pip install tomli27.9 Tableau comparatif
| Format | Binaire ? | Taille | Lecture partielle | Typé | Usage |
|---|---|---|---|---|---|
pickle | Oui | Moyenne | Non | Python uniquement | Interne, cache |
json | Non | Grande | Non | Faible | APIs, config |
msgpack | Oui | Petite | Non | Faible | Réseau, stockage compact |
parquet | Oui | Très petite | Oui (colonnes) | Fort | Data science, pandas |
hdf5 | Oui | Petite | Oui (slicing) | Moyen | Datasets ML, scientifique |
zarr | Oui | Petite | Oui (chunks) | Fort | Datasets cloud, distribué |
yaml | Non | Grande | Non | Faible | Configuration humaine |
toml | Non | Grande | Non | Faible | pyproject.toml |
27.10 Recommandations pour la thèse
- Configuration : YAML ou TOML
- Checkpoints de modèles :
pickle(PyTorch.pt/.pth) ou HDF5 - Datasets : HDF5 (petits) ou zarr (gros, cloud)
- Échange de données : msgpack (binaire) ou JSON (texte)
- DataFrame : parquet (lecture/écriture rapide, compression)
- Sauvegarde de résultats d’expériences : JSON pour la lisibilité, msgpack pour la compacité