Aide-mémoire : définir ses fonctions

Écrire ses propres fonctions avec def, paramètres, return et assert

définir et appeler paramètres et arguments return - rendre une valeur assert - tester sa fonction pièges fréquents

Définir et appeler une fonction

On définit une fonction avec le mot def, son nom, des parenthèses et un deux-points :. Le corps est indenté (un niveau plus loin). Définir ne fait rien : c'est l'appel qui exécute le code.

Structure minimale

def nom(): ... puis nom()

def saluer(): print("Bonjour la foret !") saluer() # c'est l'appel qui execute

Le deux-points est obligatoire apres les parenthèses. Tout le corps est indenté de 4 espaces. Sans l'appel saluer(), rien ne se passe.

Définir vs appeler

la définition = recette ; l'appel = cuisiner

# ceci DEFINIT (pas encore exécuté) def afficherTitre(): print("--- Résultats ---") # ceci APPELLE (exécute le code) afficherTitre() afficherTitre() # on peut rappeler

On peut appeler la même fonction plusieurs fois : c'est tout l'intérêt. On écrit le code une fois, on l'utilise autant qu'on veut.

Paramètres et arguments

Un paramètre est un nom de variable dans la définition (def). Un argument est la valeur réelle fournie à l'appel. Les paramètres permettent à la fonction de travailler sur des données différentes à chaque appel.

Un seul paramètre

def nom(parametre):

def saluerPersonne(prenom): print("Bonjour", prenom) saluerPersonne("Ada") # Bonjour Ada saluerPersonne("Newton") # Bonjour Newton

prenom est le paramètre (dans la définition). "Ada" est l'argument (à l'appel). Le paramètre prend la valeur de l'argument pour la durée de l'exécution.

Plusieurs paramètres

def nom(param1, param2):

def aireRectangle(largeur, hauteur): return largeur * hauteur aireRectangle(3, 4) # 12 aireRectangle(6, 2) # 12 aussi

Les arguments sont associés aux paramètres dans l'ordre. Ici, largeur recoit 3 et hauteur recoit 4.

TermeOù ?Exemple
Paramètredans la définition, entre les () du defdef aireRectangle(largeur, hauteur):
Argumentà l'appel, entre les () du nomaireRectangle(3, 4)

return : rendre une valeur

return renvoie une valeur à l'endroit où la fonction a été appelée et termine la fonction immédiatement. Sans return, la fonction renvoie None. C'est la différence cruciale avec print.

return vs print

return = réutilisable ; print = affiché seulement

def doubler(nombre): return nombre * 2 # renvoie la valeur resultat = doubler(5) # on reutilise la valeur print(resultat) # 10 print(doubler(3) + 1) # 7 (calcul possible)

Règle d'or : si tu veux utiliser le résultat plus loin dans le code, utilise return. Si tu veux juste montrer quelque chose à l'écran, utilise print.

Sans return : None

toute fonction sans return renvoie None

def afficherDouble(nombre): print(nombre * 2) # affiche, ne renvoie pas valeur = afficherDouble(5) # valeur est None, pas 10 ! print(valeur) # None

C'est un piège très fréquent. Si la variable reçoit None, c'est presque toujours un return oublié.

Valeurs par défaut et arguments nommés

Un paramètre peut avoir une valeur par défaut avec = dans le def. Si l'argument n'est pas fourni à l'appel, la valeur par défaut est utilisée. On peut aussi nommer les arguments à l'appel pour les passer dans n'importe quel ordre.

Valeur par défaut

def nom(param="valeur_defaut"):

def saluer(prenom, salutation="Bonjour"): return salutation + " " + prenom saluer("Ada") # Bonjour Ada saluer("Ada", "Salut") # Salut Ada

Les paramètres avec valeur par défaut doivent être après les paramètres sans défaut. On ne peut pas écrire def saluer(salutation="Bonjour", prenom):.

Arguments nommés

nom(param=valeur) à l'appel

def creerNote(matiere, note, maximum=100): return note / maximum * 100 # argument nommé : l'ordre n'importe pas creerNote(note=45, matiere="chimie")

Nommer les arguments rend le code plus lisible et évite les erreurs d'ordre quand une fonction a plusieurs paramètres.

Portée : les variables locales

Une variable créée à l'intérieur d'une fonction est locale : elle n'existe que pendant l'exécution de cette fonction et disparaît ensuite. Le code extérieur ne peut pas y accéder.

Variable locale invisible à l'extérieur

chaque appel a ses propres variables

def calculerMoyenne(liste): total = sum(liste) # total est local return total / len(liste) calculerMoyenne([10, 20, 30]) # print(total) # NameError : total n'existe plus

total existe seulement pendant l'appel. C'est une bonne chose : les fonctions ne "polluent" pas l'espace global avec leurs variables temporaires.

Chaque appel est indépendant

les paramètres repartent à zéro à chaque appel

def compterJusquA(limite): compteur = 0 for valeur in range(limite): compteur = compteur + 1 return compteur compterJusquA(5) # compteur repart de 0 compterJusquA(3) # compteur repart de 0

Chaque appel repart avec ses propres variables fraîches. Il n'y a aucune mémoire entre deux appels (sauf si on utilise une variable extérieure, mais c'est à éviter).

assert : tester ses fonctions

assert condition ne fait rien si la condition est vraie. Il lève une AssertionError si elle est fausse. C'est l'outil pour vérifier qu'une fonction produit les bons résultats avant de l'utiliser dans un programme.

Jeu d'essais de base

assert nom(arguments) == resultat_attendu

def aireRectangle(largeur, hauteur): return largeur * hauteur # cas normaux assert aireRectangle(3, 4) == 12 assert aireRectangle(0, 5) == 0 assert aireRectangle(1, 1) == 1 # si tout est silencieux : les tests passent

Écrire plusieurs assert couvrant des cas normaux, des cas limites (zéro, valeur max) et des cas inhabituels. Silence = succès.

Ce qui se passe en cas d'échec

AssertionError signale un bug dans la fonction

def aireRectangle(largeur, hauteur): return largeur + hauteur # bug : + au lieu de * assert aireRectangle(3, 4) == 12 # AssertionError ! # la fonction renvoie 7, pas 12

L'AssertionError nous signale immédiatement que la fonction est incorrecte. Mieux vaut le découvrir maintenant que lorsque le programme tourne avec de vraies données.

SituationCe qui se passeSignification
assert calcul(3) == 9 et c'est vrairien (silence)le test passe - la fonction est correcte pour ce cas
assert calcul(3) == 9 et c'est fauxAssertionErrorla fonction produit un mauvais résultat - il y a un bug

Les pièges qui font perdre du temps

Quatre erreurs très fréquentes quand on commence à écrire ses propres fonctions.

Oublier return : la fonction renvoie None

def calculerDouble(nombre): nombre * 2 # calcule mais ne renvoie pas resultat = calculerDouble(5) print(resultat) # None, pas 10 !

Le calcul est fait mais perdu. Ajoute return nombre * 2 pour que la valeur sorte de la fonction.

Oublier les () à l'appel

saluer # ne fait rien (juste le nom) saluer() # l'appel exécute la fonction

Écrire le nom sans parenthèses ne déclenche rien : Python voit juste une référence à la fonction. Les () sont obligatoires pour l'appeler.

Confondre print et return

def doubler(nombre): print(nombre * 2) # affiché, pas renvoyé total = doubler(5) + 1 # TypeError : None + 1

Ce qui est affiché avec print ne peut pas être réutilisé dans un calcul. Pour réutiliser la valeur, il faut return.

Croire qu'on modifie une variable extérieure

compteur = 0 def incrementer(): compteur = compteur + 1 # variable LOCALE incrementer() print(compteur) # toujours 0

Le compteur dans la fonction est une nouvelle variable locale, pas le compteur extérieur. Utilise return et récupère la valeur à l'extérieur.

Qui existe où ? Le tableau à garder en tête

Un seul exemple suffit. Le tableau reprend les quatre variables de ce code et dit, pour chacune, si elle existe à l'intérieur de la fonction et à l'extérieur (dans le reste du programme).

TAUX_TAXE = 0.15 # constante externe devise = "$" # variable externe normale def calculerTotal(montant): # montant : parametre recu taxe = montant * TAUX_TAXE # taxe : variable locale return montant + taxe print(calculerTotal(100), devise)
La variable Ce que c'est À l'INTÉRIEUR de calculerTotal À l'EXTÉRIEUR (reste du programme)
devise variable externe normale (globale) ✓ existe en lecture
✗ pas modifiable sans global
✓ existe
TAUX_TAXE constante externe (COMME_CECI) ✓ existe en lecture
on ne la modifie jamais
✓ existe
montant paramètre reçu ✓ existe (variable locale) ✗ n'existe pas
taxe variable créée dans la fonction (locale) ✓ existe pendant l'appel ✗ disparaît (NameError)

La règle d'or : une bonne fonction fait comme si l'extérieur n'existait pas. Tout ce qui entre passe par les paramètres, tout ce qui sort passe par le return. Une boîte avec une entrée et une sortie, pas une fenêtre ouverte sur tout le programme.