1. Modularité et principe de responsabilité unique (SRP)

Une fonction est un sous-programme autonome conçu pour accomplir une tâche spécifique et bien délimitée. En découpant une application volumineuse en fonctions modulaires, le développeur renforce la réutilisabilité, la lisibilité et la testabilité de son code.

Une fonction pure est une fonction qui satisfait deux propriétés majeures :

  • Elle retourne toujours le même résultat pour les mêmes arguments d’entrée (déterminisme).
  • Elle ne produit aucun effet de bord (side effect) : aucune mutation de variable globale, aucun appel d’I/O imprévu.

2. Paramètres, valeurs par défaut et Type Hints

Python autorise les arguments positionnels, les arguments nommés et les valeurs par défaut. L’usage conjoint du typage indicatif (Type Hints) documente formellement les contrats d’interface :

def calculer_interet_compose(
    capital: float, 
    taux_annuel: float = 0.02, 
    annees: int = 5
) -> float:
    """Calcule le capital final avec intérêts composés."""
    if capital < 0 or taux_annuel < 0 or annees < 0:
        raise ValueError("Les valeurs doivent être strictement positives.")
    return capital * ((1 + taux_annuel) ** annees)

resultat = calculer_interet_compose(10000.0, taux_annuel=0.035, annees=3)
print(f"Capital acquis : {resultat:.2f} CHF")

3. Portée des variables et règle LEGB

La résolution des identifiants en Python suit la règle hiérarchique LEGB : Local (corps de la fonction), Enclosing (fonctions englobantes), Global (module courant), Built-in (fonctions natives de Python). Une variable définie dans une fonction n'est pas accessible à l'extérieur, protégeant ainsi l'intégrité de l'état logiciel.

Synthèse pédagogique : Privilégiez systématiquement les fonctions pures : elles sont simples à tester unitairement, exemptes d'effets secondaires et facilement parallélisables.