Conseils pour écrire un code Python propre et lisible.
Comprendre les conventions Python
Le langage Python est réputé pour sa lisibilité et sa simplicité, ce qui le rend accessible même à ceux qui s’initient à la programmation. Respecter les conventions de code est essentiel pour préserver cette clarté, notamment parce que Python utilise l’indentation pour délimiter les blocs. Des conventions partagées facilitent aussi la collaboration et la maintenance : d’autres développeurs liront et comprendront votre travail plus facilement.
Ces conventions sont décrites dans le guide de style PEP 8. Il recommande par exemple des noms explicites : préférez nombre_de_jours à un simple n ou ndj, et def calculer_salaire_net(): à def csn():. Un code qui suit les usages de la communauté Python est dit « pythonique ». Laissez aussi deux lignes vides entre les fonctions et classes de premier niveau, et une seule entre les méthodes d’une classe, pour segmenter clairement votre code.
Côté documentation, les docstrings (décrites dans la PEP 257) fournissent une courte description du but d’une fonction, d’une classe ou d’un module, utile pour vous comme pour quiconque lira votre code plus tard. Enfin, une bonne gestion des exceptions, avec try, except et éventuellement else, évite qu’un programme s’arrête brutalement et permet de traiter proprement les cas inattendus.
Aujourd’hui, vous n’avez pas à tout vérifier à la main : un outil comme Ruff (linter et formateur très rapide) contrôle automatiquement une grande partie de ces règles et reformate le code pour vous.
Définir des noms de variables significatifs
Adopter de bonnes pratiques dès la première ligne est crucial, et les noms explicites en font partie. Un nom de variable doit refléter clairement la donnée qu’elle contient ; un nom de fonction doit indiquer l’action réalisée ou le résultat attendu ; un nom de classe doit dire son rôle dans le programme. Si vous créez une classe pour gérer des utilisateurs sur un site web, GestionnaireUtilisateur est plus parlant qu’un terme vague comme Donnees ou Gestion.
Un nom bien choisi permet aussi d’écrire moins de commentaires. Évitez toutefois les noms interminables, qui alourdissent la lecture. Notez que PEP 8 recommande le style snake_case (minuscules séparées par des tirets bas) pour les variables et les fonctions, et CamelCase pour les classes. Quelques exemples :
| Variable non recommandée | Variable recommandée | Raison |
|---|---|---|
d |
dossier_client |
Nom explicite décrivant la donnée |
nf |
nom_fichier |
Évite la confusion avec d’autres abréviations |
l |
liste_produits |
Précise ce que contient la variable (et l se confond avec 1) |
En fin de compte, des noms significatifs sont une règle clé de la programmation propre : ils facilitent le développement futur et font office de documentation. Les docstrings complètent le tableau en décrivant brièvement le rôle d’une fonction ou d’une classe sans qu’on ait à fouiller dans son code. Choisir de bons noms n’est pas qu’une recommandation : c’est une marque de considération pour ceux qui reliront votre code, vous-même compris.
Utilisation de l’indentation et de l’espacement
Contrairement à d’autres langages où des accolades délimitent les blocs, c’est en Python l’indentation qui définit la structure du programme. Un bloc commencé avec un niveau d’indentation doit le conserver jusqu’à sa fin. PEP 8 recommande quatre espaces par niveau, sans mélanger espaces et tabulations. Prenons un exemple :
def ma_fonction():
# Ceci est un exemple de bonne indentation
for i in range(5):
print(i)
Ici, def ma_fonction(): introduit une fonction, et la ligne indentée dessous marque le début de son bloc. De même, le print(i) aligné sous le for fait partie de la boucle. Une indentation incohérente provoque une IndentationError ou, pire, un comportement différent de celui que vous attendiez.
Côté espacement, utilisez des lignes vides pour séparer les fonctions et les blocs logiques, et évitez les espaces superflus à l’intérieur des lignes (par exemple f(x) et non f( x )). Voici la comparaison la plus simple :
# Recommandé
def fonction():
pass
# Non recommandé : une indentation incohérente ne fonctionne pas
def fonction():
pass
En résumé, une indentation et un espacement corrects clarifient la structure de vos programmes, mais aussi votre manière de penser en tant que développeur.
Appliquer le principe KISS (Keep It Simple, Stupid)
Le principe KISS, que l’on peut traduire par « gardez les choses simples », encourage à écrire des fonctions et des classes qui vont à l’essentiel. Plutôt que de multiplier les fonctionnalités dans une seule fonction, définissez des fonctions distinctes, avec des noms explicites qui clarifient leur but. Chaque bloc de code réalise alors une tâche précise et reste facile à comprendre, à tester et à déboguer.
Les commentaires doivent rester concis et utiles : une ligne décrivant le but d’une fonction est souvent suffisante. Voici un tableau pour résumer les éléments clés du principe KISS :
| Élément | Objectif |
|---|---|
| Fonctions | Réaliser des tâches uniques et bien définies |
| Noms | Être descriptifs et précis |
| Commentaires | Fournir des clarifications utiles et concises |
| Complexité | Être évitée autant que possible |
| Structure du code | Être organisée et modulaire |
Appliquons ce principe à un exemple de fonction :
def saluer_utilisateur(nom):
print(f"Bonjour, {nom} ! Bienvenue dans notre programme.")
Cette fonction fait exactement ce qu’elle annonce, sans complexité inutile.
Comprendre et utiliser les compréhensions de listes et de dictionnaires
Les compréhensions de listes et de dictionnaires permettent de construire des collections de façon concise. Prenons une boucle for qui filtre et transforme des éléments : une compréhension la réduit à une seule ligne, plus lisible.
nombres = [1, 2, 3, 4, 5, 6]
carres = [n ** 2 for n in nombres if n > 3]
# [16, 25, 36]
Ce code ne garde que les nombres supérieurs à trois et calcule leur carré. Pour les dictionnaires, la syntaxe est la même : vous transformez les valeurs en conservant (ou en modifiant) les clés.
infos = {"a": 1, "b": 2, "c": 3}
infos_doubles = {nom: valeur * 2 for nom, valeur in infos.items()}
# {'a': 2, 'b': 4, 'c': 6}
Ce segment double la valeur associée à chaque clé. Les noms infos et infos_doubles indiquent immédiatement l’objectif de chaque structure. Gardez toutefois le bon sens : si une compréhension devient trop longue ou imbriquée, une boucle classique sera plus lisible, ce qui reste l’objectif de KISS.
L’importance des commentaires
Qu’il s’agisse d’un simple script ou d’un projet de grande envergure, les commentaires aident les développeurs à suivre le fil de leur pensée ainsi que celui de leurs collaborateurs. Ils sont particulièrement utiles pour expliquer une logique complexe ou une décision qui n’est pas évidente : le pourquoi plutôt que le quoi. Un commentaire qui répète simplement le code (i += 1 # ajoute 1 à i) n’apporte rien et vieillit mal.
Les docstrings, elles, documentent les modules, classes et fonctions, et sont accessibles via help() et par les éditeurs. Associées à des annotations de type (def saluer(nom: str) -> None:), elles constituent une documentation intégrée au code, précieuse pour un projet qui grandit.
Utilisation correcte des exceptions
Utiliser les exceptions de manière appropriée est essentiel pour obtenir un code robuste. Vous pouvez placer dans un bloc try le code susceptible de générer une erreur, puis utiliser except pour définir la réponse à cette erreur : cela évite une fin inattendue du programme et permet d’afficher un message lisible ou de déclencher une action de récupération.
Restez spécifique : au lieu d’un except général qui capture tout, attrapez les exceptions que vous savez traiter. Vous saurez mieux quelles erreurs votre code prévoit de gérer, et le débogage sera plus rapide. Exemple :
def diviser(a, b):
"""Divise a par b et renvoie le résultat, ou None si b vaut zéro."""
try:
resultat = a / b
except ZeroDivisionError:
print("Erreur : division par zéro impossible.")
return None
else:
return resultat
Le bloc try contient uniquement l’opération qui peut échouer, except gère l’erreur précise attendue, et else n’est exécuté que si aucune exception n’a été levée. Une docstring peut aussi préciser les exceptions qu’une fonction est susceptible de lever.
Observer le principe DRY (Don’t Repeat Yourself)
Le principe DRY, « ne vous répétez pas », incite à écrire des fonctions réutilisables plutôt que de dupliquer des blocs de code. Si vous devez formater et afficher des données utilisateur à plusieurs endroits, définissez une fonction unique afficher_utilisateur(data) et appelez-la partout où c’est nécessaire.
def afficher_utilisateur(data):
"""Affiche un résumé de l'utilisateur."""
nom = data["nom"]
print(f"Nom d'utilisateur : {nom}")
# Utilisation de la fonction pour éviter le code redondant
donnees_utilisateur = {"nom": "Alice"}
afficher_utilisateur(donnees_utilisateur)
Le code est plus modulaire : si le format change, vous ne modifiez que la fonction afficher_utilisateur au lieu de chercher chaque copie du code. Voici une comparaison entre démarche DRY et non-DRY :
| Méthode | Avantages | Inconvénients |
|---|---|---|
| DRY | Moins de code à maintenir, mise à jour facilitée, moins d’erreurs | Demande un peu de réflexion initiale |
| Non-DRY | Plus rapide à écrire au départ | Code difficile à maintenir, mises à jour lourdes, risque d’erreurs élevé |
Pour appliquer DRY :
- Identifiez les blocs de code répétitifs.
- Écrivez des fonctions pour encapsuler ces répétitions.
- Remplacez la redondance par des appels de fonction.
- Utilisez les docstrings pour expliquer le but et l’utilisation des fonctions.
Astuce : ne copiez pas deux fois la même logique. Utilisez des fonctions pour abstraire et réutiliser votre code.
Pensez à votre code comme à une boîte à outils : plutôt que d’acheter un nouvel outil pour chaque tâche, vous réutilisez ceux que vous possédez déjà. Évitez cependant de factoriser trop tôt : deux morceaux de code qui se ressemblent par hasard ne méritent pas toujours d’être fusionnés.
Organisation de votre code avec des fonctions et classes
Les fonctions sont des blocs de code réutilisables, définis avec le mot-clé def. Elles divisent un programme en segments qui exécutent chacun une tâche précise. Les classes, outils de la programmation orientée objet, regroupent des données et des fonctions (des méthodes) dans un élément réutilisable. Fonctions et classes aident à éviter la répétition de code, comme le recommande DRY, et transforment un script en code lisible et bien organisé.
Prenons l’exemple d’une classe Voiture qui encapsule des données (couleur, marque, modèle) et des comportements (démarrer, arrêter) :
class Voiture:
def __init__(self, couleur, marque, modele):
self.couleur = couleur
self.marque = marque
self.modele = modele
def demarrer(self):
print(f"La {self.marque} {self.modele} démarre")
def arreter(self):
print(f"La {self.marque} {self.modele} s'arrête")
Pour ce type de classe qui ne contient surtout que des données, Python propose aussi les dataclasses (module dataclasses), qui génèrent automatiquement __init__ et d’autres méthodes. Respecter ces principes vous fera gagner du temps sur le long terme et améliorera la qualité de votre code.
Aller plus loin
Pour progresser sur ces bonnes pratiques avec un accompagnement, découvrez la formation Python à distance.