Les fonctions en Python

@joekakone

Joseph Konka @joekakone

03/03/2026 · 11 min

Apprenez à concevoir des fonctions modulaires en Python : paramètres positionnels et nommés, valeurs par défaut, piège des arguments mutables, arguments variables (*args, **kwargs) et règle de portée LEGB.

Les fonctions en langage Python#

En programmation, une fonction est un bloc d'instructions nommé, autonome et réutilisable, conçu pour accomplir une tâche spécifique. L'utilisation des fonctions répond au principe fondamental DRY (Don't Repeat Yourself — Ne vous répétez pas) : plutôt que de copier-coller un bloc de 10 lignes à plusieurs endroits de votre code, vous le factorisez au sein d'une fonction unique.

En Python, les fonctions sont des citoyennes de première classe (first-class citizens) : elles peuvent être assignées à des variables, passées en argument d'autres fonctions et retournées comme résultats.


1. Définition et anatomie d'une fonction#

On définit une fonction à l'aide du mot-clé def, suivi de son nom, de parenthèses listant ses paramètres, et d'un deux-points : :

def calculer_perimetre_rectangle(longueur: float, largeur: float) -> float:
    """Calcule le périmètre d'un rectangle.

    Args:
        longueur (float): La longueur du rectangle en mètres.
        largeur (float): La largeur du rectangle en mètres.

    Returns:
        float: Le périmètre total.
    """
    perimetre = 2 * (longueur + largeur)
    return perimetre

# Appel de la fonction
resultat = calculer_perimetre_rectangle(10.5, 4.0)
print(f"Perimetre : {resultat} m")  # 29.0 m

[!NOTE] Le rôle de la docstring (PEP 257) :
La chaîne de caractères située immédiatement sous la signature de la fonction est sa documentation officielle (docstring). Elle est accessible à tout moment via help(ma_fonction) ou ma_fonction.__doc__ et est exploitée par les IDE pour afficher l'aide contextuelle.


2. Arguments positionnels vs Arguments nommés (Keywords)#

Lors de l'appel d'une fonction, vous pouvez transmettre les valeurs selon deux modes :

def creer_utilisateur(nom: str, role: str = "visiteur", actif: bool = True) -> dict:
    return {"nom": nom, "role": role, "actif": actif}

# 1. Arguments positionnels (l'ordre compte)
u1 = creer_utilisateur("Alice", "admin", True)

# 2. Arguments nommés (l'ordre n'a plus d'importance, clarté maximale)
u2 = creer_utilisateur(role="analyste", nom="Bob", actif=False)

# 3. Utilisation des valeurs par défaut
u3 = creer_utilisateur("Charlie")  # role="visiteur", actif=True

3. Le piège absolu de l'argument par défaut mutable#

Considérez cette fonction écrite innocemment :

# ATTENTION : BOGUE CLASSIQUE TRÈS DANGEREUX
def ajouter_tache(tache: str, liste_taches: list = []):
    liste_taches.append(tache)
    return liste_taches

print(ajouter_tache("Rédiger rapport"))  # ['Rédiger rapport']
print(ajouter_tache("Envoyer email"))    # ['Rédiger rapport', 'Envoyer email'] -> SURPRISE !

Pourquoi ce comportement ?#

En Python, les valeurs par défaut des fonctions ne sont pas évaluées à chaque appel, mais une seule fois lors de la compilation du fichier ! La liste [] est un objet unique partagé entre tous les appels ultérieurs.

La solution idiomatique : None comme sentinelle#

Pour tout argument par défaut dont le type est mutable (list, dict, set), utilisez toujours None par défaut :

# Approche correcte et sécurisée :
def ajouter_tache(tache: str, liste_taches: list = None) -> list:
    if liste_taches is None:
        liste_taches = []  # Une nouvelle liste est créée à chaque appel
    liste_taches.append(tache)
    return liste_taches

4. Nombre arbitraire d'arguments : *args et **kwargs#

Lorsque vous ignorez à l'avance combien d'arguments l'utilisateur va fournir :

A. Les arguments positionnels variables : *args#

L'opérateur étoile rassemble tous les arguments positionnels supplémentaires dans un tuple :

def calculer_moyenne(*nombres: float) -> float:
    """Accepte n'importe quel nombre de paramètres numériques."""
    if not nombres:
        return 0.0
    return sum(nombres) / len(nombres)

print(calculer_moyenne(12, 14, 16))        # 14.0
print(calculer_moyenne(10, 20, 30, 40, 50)) # 30.0

B. Les arguments nommés variables : **kwargs#

Le double astérisque rassemble tous les arguments nommés supplémentaires sous forme d'un dictionnaire :

def afficher_configuration(nom_serveur: str, **options) -> None:
    print(f"Configuration du serveur : {nom_serveur}")
    for cle, valeur in options.items():
        print(f"  - {cle} = {valeur}")

afficher_configuration("Production-01", port=8080, ssl=True, timeout=30)

5. Portée des variables et règle LEGB#

Où Python recherche-t-il la valeur d'une variable lorsqu'elle est sollicitée ? Il applique la règle de résolution LEGB :

flowchart TD
    L[1. Local : Variables définies à l'intérieur de la fonction] --> E
    E[2. Enclosing : Variables d'une fonction englobante / closure] --> G
    G[3. Global : Variables définies au niveau du module .py] --> B
    B[4. Built-in : Fonctions et types natifs Python : print, len, range]
x = "Globale"

def fonction_externe():
    x = "Enclosing"

    def fonction_interne():
        x = "Local"
        print("Interne :", x)  # Affiche "Local"

    fonction_interne()
    print("Externe :", x)      # Affiche "Enclosing"

fonction_externe()
print("Module   :", x)          # Affiche "Globale"

6. Sommaire des leçons de la Partie 3#

  1. Les fonctions fondamentales (cette leçon) : signatures, passage d'arguments et portée.
  2. Les fonctions récursives : cas de base, pile d'appels et récursion terminale.
  3. Les fonctions anonymes (lambda) : fonctions à expression unique, map, filter et tris avancés.

7. Défi d'application#

Écrivez une fonction formater_coordonnees(*coordonnees: float, separateur: str = " | ") -> str qui accepte un nombre arbitraire de coordonnées numériques flottantes et retourne une chaîne de caractères où chaque nombre est formaté avec deux décimales, séparés par la chaîne separateur.

Commentaires

Inscrivez-vous à une formation complète

Voir le catalogue