Skip to content
Learni
Voir tous les tutoriels
Outils Backend

Comment utiliser Protobuf avec Python en 2026

Read in English

Introduction

Protocol Buffers, ou Protobuf, est un format de sérialisation binaire développé par Google, conçu pour être plus compact et rapide que JSON ou XML. Contrairement à JSON qui est textuel et verbeux, Protobuf produit des données binaires typées, réduisant la taille de 3 à 10 fois et accélérant le parsing de 5 à 20 fois selon les benchmarks.

C'est idéal pour les microservices, gRPC, IoT ou tout système nécessitant une communication efficace. En 2026, avec l'essor des APIs à haute performance et l'IA embarquée, Protobuf reste un standard industriel supporté par tous les langages majeurs.

Ce tutoriel beginner vous guide pas à pas : de l'installation à des exemples concrets en Python. À la fin, vous saurez créer, compiler et utiliser des messages Protobuf pour des applications réelles, comme un échange de données Person entre client et serveur. Chaque étape est actionable avec code complet.

Prérequis

  • Python 3.10 ou supérieur installé
  • pip (généralement inclus avec Python)
  • Système Unix-like (Linux/macOS) ou WSL sur Windows pour protoc
  • Connaissances basiques en Python (classes, imports)
  • Un éditeur de code comme VS Code

Installer protoc

install-protoc.sh
# Pour macOS avec Homebrew
brew install protobuf

# Pour Ubuntu/Debian
sudo apt update
sudo apt install protobuf-compiler

# Vérification
protoc --version
# Doit afficher libprotoc 27.3 ou supérieur

protoc est le compilateur de schémas Protobuf. Cette commande installe la version stable 2026-ready. Sur Windows, téléchargez le binaire depuis GitHub releases et ajoutez-le au PATH. Vérifiez toujours la version pour compatibilité avec vos plugins.

Définir votre premier schéma Protobuf

Un schéma .proto définit la structure des données comme un contrat typé. Pensez-y comme à un JSON Schema mais binaire et versionnable.

Nous créons un message simple Person avec nom, ID et email. Les champs sont numérotés pour la rétrocompatibilité : changer le type d'un champ existant casse les anciens messages, mais ajouter un nouveau champ est sûr si numéroté séquentiellement.

Premier fichier .proto

person.proto
syntax = "proto3";

package tutorial;

message Person {
  int32 id = 1;
  string name = 2;
  string email = 3;
}

Ce schéma utilise proto3 (syntaxe moderne, sans 'required'). Le package évite les collisions. Les numéros de champs (1,2,3) sont cruciaux pour l'évolution : ne les réutilisez jamais. Copiez ce fichier tel quel.

Compiler le schéma en Python

compile.sh
pip install protobuf

protoc --python_out=. person.proto

# Vérification : fichier généré
ls *.pb2.py

La commande génère person_pb2.py, un module Python pur avec classes typées. pip install protobuf fournit le runtime. Le flag --python_out=. place le fichier dans le dossier courant. Exécutez dans le même répertoire que person.proto.

Utiliser le message en Python

Une fois compilé, importez le module généré. Créez un objet Person, sérialisez-le en bytes (comme un 'pack'), puis désérialisez ('unpack'). C'est 10x plus rapide que json.dumps/loads pour de gros volumes.

Script d'encodage/décodage simple

use_person.py
import person_pb2

# Créer un message
person = person_pb2.Person()
person.id = 1234
person.name = "Alice"
person.email = "alice@example.com"

# Sérialiser en bytes
serialized = person.SerializeToString()
print(f"Taille sérialisée: {len(serialized)} bytes")
print(f"Bytes: {serialized}")

# Désérialiser
from_bytes = person_pb2.Person()
from_bytes.ParseFromString(serialized)
print(f"ID: {from_bytes.id}, Nom: {from_bytes.name}, Email: {from_bytes.email}")

Ce script complet est exécutable après compilation (python use_person.py). SerializeToString() produit des bytes compacts (env. 20 bytes ici vs 50+ en JSON). ParseFromString() reconstruit l'objet sans perte. Piège : oubliez HasField() pour champs optionnels en proto2.

Schémas complexes avec messages imbriqués

Analogie : comme des classes Python nested. Ajoutons un PhoneNumber répété dans Person, et un enum PhoneType. Les repeated fields sont des listes dynamiques, parfaites pour arrays.

Schéma avancé avec nested et enum

addressbook.proto
syntax = "proto3";

package tutorial;

enum PhoneType {
  MOBILE = 0;
  HOME = 1;
  WORK = 2;
}

message PhoneNumber {
  string number = 1;
  PhoneType type = 2;
}

message Person {
  int32 id = 1;
  string name = 2;
  string email = 3;
  repeated PhoneNumber phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}

Enum pour types fermés, repeated pour 1-N, messages nested pour composition. AddressBook est un conteneur. Les numéros sautent (4 après 3) pour futures ajouts. proto3 gère les zéros par défaut automatiquement.

Compiler le schéma avancé

compile_advanced.sh
protoc --python_out=. addressbook.proto

# Vérification
ls addressbook_pb2.py

Même processus, génère addressbook_pb2.py avec classes imbriquées. Pas de plugin extra needed pour Python basique. Si erreur 'protoc: not found', revenez à l'installation.

Script complet avec nested messages

use_addressbook.py
import addressbook_pb2

# Créer AddressBook
book = addressbook_pb2.AddressBook()

# Première personne
person1 = book.people.add()
person1.id = 1234
person1.name = "Alice"
person1.email = "alice@example.com"
phone1 = person1.phones.add()
phone1.number = "+33123456789"
phone1.type = addressbook_pb2.AddressBook_PHONE_TYPE_MOBILE

# Deuxième personne
person2 = book.people.add()
person2.id = 5678
person2.name = "Bob"
person2.email = "bob@example.com"
phone2 = person2.phones.add()
phone2.number = "+33198765432"
phone2.type = addressbook_pb2.AddressBook_PHONE_TYPE_WORK

# Sérialiser
data = book.SerializeToString()
print(f"Taille totale: {len(data)} bytes")

# Désérialiser
new_book = addressbook_pb2.AddressBook()
new_book.ParseFromString(data)
for person in new_book.people:
    print(f"Personne: {person.name} ({person.email})")
    for phone in person.phones:
        type_str = "Mobile" if phone.type == addressbook_pb2.AddressBook_PHONE_TYPE_MOBILE else "Work" if phone.type == addressbook_pb2.AddressBook_PHONE_TYPE_WORK else "Home"
        print(f"  Téléphone: {phone.number} ({type_str})")

Script exécutable autonome : ajoute via .add() pour repeated. Enums via constantes générées (_PHONE_TYPE_MOBILE). Taille ~100 bytes vs 300+ JSON. Idéal pour stockage ou réseau. Évitez muter après sérialisation.

Bonnes pratiques

  • Numérotez séquentiellement : 1-15 pour champs fréquents (plus compacts), réservez >19000 pour optionnels.
  • Évitez les strings longs : utilisez bytes pour base64 si besoin.
  • Versionnez les .proto : utilisez git tags et semantic versioning pour schémas.
  • Validez avant compilation : protoc --decode pour tester bytes manuellement.
  • Intégrez à gRPC : passez au service RPC après maîtrise des messages.

Erreurs courantes à éviter

  • Numéros de champs réutilisés : casse la rétrocompatibilité, les parsers anciens échouent.
  • Oublier proto3 syntax : proto2 a 'required' rigide, migrez vers proto3.
  • Ignorer les imports : pour multi-fichiers, utilisez import public "autre.proto".
  • Pas de gestion d'erreurs : toujours wrap ParseFromString() dans try/except pour données corrompues.

Pour aller plus loin

  • Documentation officielle : Protobuf Python
  • Tutoriel gRPC : intégrez ces messages à des services RPC.
  • Outils avancés : Buf CLI pour build automatisé, ou protobuf-es pour web.
  • Formations Learni : maîtrisez gRPC et microservices en profondeur avec nos experts.