L’instruction pass en Python est minuscule, mais elle évite pas mal de code bancal quand une structure doit exister avant d’être réellement remplie. Je vais montrer à quoi elle sert vraiment, quand je l’utilise dans un projet backend ou un script d’automatisation, et surtout quand il vaut mieux la remplacer par quelque chose de plus explicite. J’irai aussi sur les confusions les plus fréquentes avec continue, break et ..., parce que c’est souvent là que les erreurs commencent.
L’essentiel à retenir sur pass en Python
-
passne produit aucun effet, mais il rend un bloc syntaxiquement valide. - Je l’utilise surtout pour des squelettes de classes, de fonctions ou de branches temporaires.
- Dans un code de production, un
passmal placé peut masquer un vrai problème logique. -
passn’a rien à voir aveccontinue,breakoureturn None. - Quand l’absence d’implémentation doit être visible, je préfère souvent lever
NotImplementedError.
Ce que fait vraiment pass en Python
La documentation officielle Python le dit sans détour: pass ne fait rien. Ce n’est pas une fonction, pas un raccourci caché, pas une instruction qui “attend” quelque chose en arrière-plan. C’est simplement une opération nulle, utile quand la syntaxe exige une instruction, mais que le programme n’a encore rien à exécuter.
En pratique, cela sert à construire un bloc valide sans lui donner de comportement pour l’instant. C’est souvent le cas quand on pose l’ossature d’une classe ou d’une fonction avant d’implémenter la logique métier.
class EmptyService:
pass
def parse_payload(payload):
passSans cette instruction, Python refuse le bloc vide. Avec elle, le code reste lisible et le squelette peut vivre le temps de la conception. La vraie question devient alors moins “qu’est-ce que fait pass ?” que “dans quels blocs son absence d’action est-elle réellement utile ?”.
À partir de là, je sépare toujours le placeholder temporaire du code qui doit exprimer une intention claire.
Quand je l’utilise dans des structures vides
pass est surtout pertinent quand je veux garder une structure syntaxiquement correcte sans simuler une logique qui n’existe pas encore. Je m’en sers rarement comme solution finale, davantage comme marqueur de travail en cours ou comme point d’ancrage pour une architecture encore incomplète.
Pour esquisser une classe ou un service
Quand je définis une interface, un modèle ou un adaptateur, il arrive que la structure soit prête alors que l’implémentation ne l’est pas encore. Dans ce cas, un bloc vide reste acceptable tant qu’il reste temporaire.
class CacheAdapter:
passCe genre de squelette est utile en phase de design, surtout dans un backend où plusieurs composants se construisent en parallèle. Mais si la classe est déjà utilisée par d’autres modules, je préfère éviter de la laisser vide trop longtemps.
Pour réserver une branche conditionnelle
Dans une condition, pass signifie souvent “je sais qu’il y a un cas, mais je n’ai rien à faire ici”. C’est pratique pour prototyper une feature flag, une branche métier ou un cas encore en cours de décision.
if feature_enabled:
run_new_flow()
else:
passJe trouve cette forme acceptable pendant le développement, mais en code mature, un else vide attire souvent la question suivante: pourquoi cette branche existe-t-elle encore ? Si elle n’a pas de raison d’être, je la supprime.
Pour laisser un bloc except vraiment assumé
On voit parfois pass dans un except, mais c’est une zone où il faut être rigoureux. Ignorer une erreur peut être légitime si l’absence de dépendance est attendue, mais cela peut aussi masquer un bug sérieux.
try:
import orjson as jsonlib
except ImportError:
passCe type d’écriture ne me convient que si une autre branche prend le relais plus bas dans le code. Sinon, je préfère un fallback explicite, un log ou un rethrow. Autrement dit, pass peut être propre, mais il ne doit jamais devenir un trou noir de diagnostic.
Cette logique d’usage vaut encore plus quand on passe d’un prototype à un vrai service exposé aux utilisateurs ou aux autres équipes.

Exemples concrets pour un backend ou un script d’automatisation
Dans un contexte web, pass apparaît souvent au moment où l’on structure un module avant d’avoir fini le comportement. Je le vois dans des adaptateurs, des hooks, des classes de service ou des points d’extension prévus pour plus tard. L’intérêt est simple: garder un code importable et lisible sans inventer une logique artificielle.
Quand la classe existe avant sa logique
Dans une API, on peut préparer une classe de service ou un client externe avant d’implémenter la connexion réelle.
class BillingClient:
def connect(self):
pass
def charge(self, amount):
passPour un prototype, cela passe. Pour une branche stable, en revanche, je préfère souvent lever une erreur explicite si la méthode n’est pas censée être appelée tout de suite.
def connect(self):
raise NotImplementedError("connect() doit être implémentée")Cette variante dit nettement plus de choses au lecteur et à l’équipe. Elle ne laisse aucune ambiguïté sur l’état du code.
Quand une fonctionnalité est planifiée mais pas encore livrée
Dans un script d’automatisation, il m’arrive de poser une branche vide pour garder le flux principal clair pendant que je termine une intégration, un traitement de fichier ou une adaptation à un format externe.
for item in items:
if item.is_deprecated():
pass
else:
process(item)Ce code peut être toléré au début, mais si le cas “deprecated” est censé devenir important, je préfère l’annoter explicitement avec un commentaire utile ou une vraie action. Le silence pur n’est intéressant que s’il est temporaire.
Lire aussi : Chemins Python - Maîtrisez pathlib et os.path pour un code robuste
Quand un point d’extension doit rester stable
Je rencontre aussi pass dans des hooks, des classes abstraites légères ou des prototypes d’architecture. Dans ce contexte, il sert à garder la signature publique stable pendant que le contenu évolue.
def before_save(record):
passLe bénéfice est surtout organisationnel: le fichier reste cohérent, les appels restent valides, et l’équipe voit immédiatement qu’un emplacement est réservé. Mais plus le projet avance, plus ce placeholder doit être remplacé par une vraie intention.
La frontière entre un placeholder sain et un faux bon réflexe devient plus claire quand on compare pass aux autres instructions souvent confondues avec lui.
pass, continue, break et ... ne jouent pas le même rôle
Je vois encore souvent ces quatre éléments mélangés, alors qu’ils ne répondent pas du tout au même besoin. Le plus simple est de les comparer côte à côte.
| Élément | Nature | Effet | Usage typique | Risque principal |
|---|---|---|---|---|
pass |
Instruction | Ne fait rien | Squelette de classe, fonction ou branche temporaire | Laisser un trou logique dans le code final |
continue |
Instruction de boucle | Passe à l’itération suivante | Filtrer un élément dans une boucle | Inutilisable hors boucle |
break |
Instruction de boucle | Quitte la boucle | Arrêter un parcours dès qu’une condition est remplie | Inutilisable hors boucle |
... |
Expression littérale | Placeholder conventionnel | Stubs, prototypes, fichiers de typage | Ne veut pas dire la même chose que pass
|
return None |
Instruction de retour | Termine la fonction avec une valeur explicite | Dire clairement qu’aucun résultat utile n’est renvoyé | À confondre avec un simple bloc vide |
Le point qui change tout, c’est que continue et break pilotent l’exécution d’une boucle, alors que pass n’oriente rien du tout. Quant à ..., la documentation Python précise qu’il n’a pas de sens spécial dans ce contexte: on l’utilise parfois par convention, mais ce n’est pas l’équivalent strict de pass.
Si je veux que le lecteur comprenne que “rien n’est fait ici”, je choisis pass. Si je veux qu’il comprenne que le code doit changer de flux, je prends autre chose. Cette différence paraît minime, mais elle évite pas mal de malentendus lors des revues de code.
Les erreurs que je vois le plus souvent
Le vrai problème n’est pas pass en lui-même. C’est l’usage trop confortable qu’on en fait quand on veut éviter de trancher une décision technique. Voici les erreurs que je retrouve le plus souvent.
-
Laisser un
passen production par oubli alors qu’une logique métier devait être ajoutée. -
Utiliser
passpour masquer une exception sans journalisation, sans fallback et sans signal clair. -
Le confondre avec
continuedans une boucle, alors que le comportement attendu est complètement différent. -
Le garder dans une fonction censée renvoyer un résultat, ce qui finit en flux silencieux ou en valeur implicite
None. -
Écrire
while True: passdans un contexte réel, ce qui peut monopoliser un cœur CPU au lieu d’attendre proprement.
Ce dernier cas est emblématique. Il est valide, mais rarement malin hors d’un exemple de documentation ou d’un besoin très particulier. En pratique, je préfère un mécanisme d’attente explicite: sommeil court, événement, blocage sur file, ou logique asynchrone plus nette.
Pour les erreurs silencieuses, ma règle est simple: si le bloc vide signifie “c’est normal”, je l’écris clairement; si le bloc vide signifie “ce n’est pas encore fait”, je le rends visible; si le bloc vide signifie “je ne sais pas”, alors il ne devrait pas rester vide.
Cette discipline rend le code plus sûr, surtout dans les services exposés à des données externes ou à des dépendances optionnelles.
Quand le garder et quand le remplacer
Je garde pass quand il protège une structure temporaire, une interface en construction ou un emplacement de code volontairement vide pendant une phase de travail. Je le remplace quand la logique manque réellement, quand une erreur doit remonter, ou quand l’intention peut être écrite plus clairement par une exception, un retour explicite ou une vraie implémentation.
- Je le garde pour un squelette de classe, de fonction ou de branche encore en chantier.
- Je le remplace par
raise NotImplementedErrorsi la méthode ne doit pas être appelée avant d’être implémentée. - Je le remplace par un fallback, un log ou un traitement réel si l’absence d’action serait ambiguë.
- Je le supprime si le bloc vide n’apporte plus aucune valeur de lecture.
Au fond, pass est un outil de structure, pas une stratégie d’implémentation. Plus le code mûrit, plus il doit disparaître des zones critiques au profit d’une intention lisible, d’un comportement concret ou d’une erreur volontairement assumée.