Bonnes pratiques & PEP 8

Coder
proprement

Conventions PEP 8, clean code, principes SOLID, type hints et outils de qualité.

Conventions de nommage

Variables & fonctions
snake_case
nom_utilisateur, calculer_total()
Classes
PascalCase
Utilisateur, GestionnaireRéseau
Constantes
SCREAMING_SNAKE
MAX_TENTATIVES, PI, URL_API
Modules & packages
minuscules
utils.py, mon_module/
Attribut privé
_un_underscore
_donnée_interne (convention)
Attribut très privé
__deux_underscores
__mangling → _Classe__attr
✗ Mauvais
# Noms non descriptifs
def f(x, y):
    return x + y

l = [1, 2, 3]
N = 100

class gestion_utilisateur:
    pass
✓ Bon
# Noms explicites
def additionner(a: int, b: int) -> int:
    return a + b

nombres = [1, 2, 3]
MAX_UTILISATEURS = 100

class GestionUtilisateur:
    pass

Formatage & indentation

✗ Mauvais
# Espaces incohérents
x=1+2
y = x *3

# Pas d'espace après virgule
lst = [1,2,3]

# Parenthèses superflues
if (x > 0):
    return (True)

# Comparaison à True/None
if actif == True:
    pass
if val == None:
    pass
✓ Bon
# Espaces autour des opérateurs
x = 1 + 2
y = x * 3

# Espace après virgule
lst = [1, 2, 3]

# Pas de parenthèses inutiles
if x > 0:
    return True

# Comparaison idiomatique
if actif:
    pass
if val is None:
    pass

Longueur de ligne

PEP 8 recommande 79 caractères max. En pratique, 88-100 est acceptable (Black utilise 88).

✗ Ligne trop longue
résultat = une_fonction_longue(argument_un, argument_deux, argument_trois, argument_quatre)
✓ Coupé proprement
résultat = une_fonction_longue(
    argument_un,
    argument_deux,
    argument_trois,
    argument_quatre,   # virgule finale ok
)

Commentaires & Docstrings

💡

Un bon code se lit sans commentaires. Commenter le pourquoi, pas le quoi. # incrémenter i de 1 est inutile. # cas limite : liste vide retourne None selon spec est utile.

Docstrings — format Google (recommandé)
def calculer_moyenne(valeurs: list[float]) -> float:
    """Calcule la moyenne arithmétique d'une liste de valeurs.

    Args:
        valeurs: Liste de nombres réels. Ne doit pas être vide.

    Returns:
        La moyenne des valeurs.

    Raises:
        ValueError: Si la liste est vide.

    Example:
        >>> calculer_moyenne([1.0, 2.0, 3.0])
        2.0
    """
    if not valeurs:
        raise ValueError("La liste ne peut pas être vide")
    return sum(valeurs) / len(valeurs)

Fonctions propres

Une seule responsabilité — si on ne peut pas résumer en une phrase, c'est trop.
Petite — idéalement ≤ 20 lignes. Au-delà, diviser.
Nom de verbecalculer_total(), valider_email(), charger_config().
≤ 3 paramètres — au-delà, regrouper dans un objet ou dataclass.
Pas d'effets de bord cachés — si une fonction modifie l'état global, le nom doit l'indiquer.
✗ Mauvais — plusieurs responsabilités
def traiter_utilisateur(données):
    # valide, sauvegarde ET envoie email
    if not données["email"]:
        raise ValueError()
    bd.sauvegarder(données)
    email.envoyer(données["email"])
✓ Bon — responsabilité unique
def valider_utilisateur(données): ...
def sauvegarder_utilisateur(données): ...
def notifier_utilisateur(email): ...

Principes SOLID

S

Single Responsibility

Une classe = une seule raison de changer. Rapport ne devrait pas gérer à la fois le calcul et l'impression.

O

Open / Closed

Ouvert à l'extension, fermé à la modification. Ajouter une fonctionnalité = créer une sous-classe, pas modifier le code existant.

L

Liskov Substitution

Une sous-classe doit pouvoir remplacer sa classe parente sans casser le programme. Si Carré hérite de Rectangle mais casse le comportement, c'est un problème.

I

Interface Segregation

Plusieurs petites interfaces valent mieux qu'une grosse. Ne pas forcer une classe à implémenter des méthodes dont elle n'a pas besoin.

D

Dependency Inversion

Dépendre d'abstractions, pas de classes concrètes. Injecter les dépendances plutôt que les instancier dans la classe.

# ✗ Dépendance concrète
class Service:
    def __init__(self):
        self.bd = MySQL()  # couplé !

# ✓ Injection de dépendance
class Service:
    def __init__(self, bd: BaseDeDonnées):
        self.bd = bd

DRY & KISS

DRY

Don't Repeat Yourself

Toute connaissance doit avoir une représentation unique dans le système. Si vous copiez-collez du code, c'est un signal à extraire une fonction.

✗ Répétition
prix_ht = 100
tva_1 = prix_ht * 0.14975
prix_ht_2 = 200
tva_2 = prix_ht_2 * 0.14975
✓ DRY
TVA = 0.14975
def calculer_tva(prix_ht):
    return prix_ht * TVA
KISS

Keep It Simple, Stupid

La solution la plus simple qui fonctionne est généralement la meilleure. Éviter la sur-ingénierie.

✗ Sur-ingénierie
class StringReverserFactory:
    def create_reverser(self):
        return StringReverser()

class StringReverser:
    def reverse(self, s): return s[::-1]
✓ KISS
def inverser_chaîne(s: str) -> str:
    return s[::-1]

Type hints

Facultatifs mais très recommandés. Améliorent la lisibilité, permettent l'autocomplétion IDE, et détectent les erreurs avec mypy.

Python 3.10+
# Types de base
def saluer(nom: str, fois: int = 1) -> str:
    return nom * fois

# Types composés (Python 3.9+ : list, dict directement)
def moyennes(scores: list[float]) -> dict[str, float]:
    return {"moy": sum(scores) / len(scores)}

# Optionnel (valeur ou None)
def trouver(lst: list[int], cible: int) -> int | None:
    try: return lst.index(cible)
    except ValueError: return None

# Callable
from collections.abc import Callable
def appliquer(f: Callable[[int], int], x: int) -> int:
    return f(x)

# Dataclass — structure typée légère
from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float
    label: str = ""   # valeur par défaut

p = Point(1.0, 2.0)
p.x, p.y  # accès direct

Linters & formatters

OutilRôleCommande
blackFormateur automatique (opinionné, PEP 8)black .
flake8Linter — détecte les violations PEP 8flake8 .
pylintAnalyse statique avancéepylint mon_module/
mypyVérification des types statiquesmypy .
isortTrier les imports automatiquementisort .
pre-commitExécuter les outils avant chaque commitpre-commit install
💡

Configurer black + flake8 + mypy dans VS Code pour avoir le retour en temps réel. Ajouter pre-commit pour s'assurer que le code commité respecte toujours les standards.

Cheat sheet

Nommage PEP 8

Variable / fonctionsnake_case
ClassePascalCase
ConstanteSCREAMING_SNAKE
Privé_underscore
Moduleminuscules

SOLID en un mot

SUne responsabilité
OÉtendre, pas modifier
LSubstituabilité
IInterfaces petites
DInjecter les dépendances

Principes généraux

DRYNe pas se répéter
KISSGarder simple
YAGNINe pas anticiper
CommenterLe pourquoi, pas le quoi
DocstringArgs / Returns / Raises