Structure minimale
def nom(): ... puis nom()
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.
Écrire ses propres fonctions avec def, paramètres, return et assert
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.
def nom(): ... puis nom()
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.
la définition = recette ; l'appel = cuisiner
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.
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.
def nom(parametre):
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.
def nom(param1, param2):
Les arguments sont associés aux paramètres dans l'ordre. Ici, largeur recoit 3 et hauteur recoit 4.
| Terme | Où ? | Exemple |
|---|---|---|
| Paramètre | dans la définition, entre les () du def | def aireRectangle(largeur, hauteur): |
| Argument | à l'appel, entre les () du nom | aireRectangle(3, 4) |
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 = réutilisable ; print = affiché seulement
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.
toute fonction sans return renvoie None
C'est un piège très fréquent. Si la variable reçoit None, c'est presque toujours un return oublié.
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.
def nom(param="valeur_defaut"):
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):.
nom(param=valeur) à l'appel
Nommer les arguments rend le code plus lisible et évite les erreurs d'ordre quand une fonction a plusieurs paramètres.
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.
chaque appel a ses propres variables
total existe seulement pendant l'appel. C'est une bonne chose : les fonctions ne "polluent" pas l'espace global avec leurs variables temporaires.
les paramètres repartent à zéro à chaque appel
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 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.
assert nom(arguments) == resultat_attendu
Écrire plusieurs assert couvrant des cas normaux, des cas limites (zéro, valeur max) et des cas inhabituels. Silence = succès.
AssertionError signale un bug dans la fonction
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.
| Situation | Ce qui se passe | Signification |
|---|---|---|
assert calcul(3) == 9 et c'est vrai | rien (silence) | le test passe - la fonction est correcte pour ce cas |
assert calcul(3) == 9 et c'est faux | AssertionError | la fonction produit un mauvais résultat - il y a un bug |
Quatre erreurs très fréquentes quand on commence à écrire ses propres fonctions.
Le calcul est fait mais perdu. Ajoute return nombre * 2 pour que la valeur sorte de 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.
Ce qui est affiché avec print ne peut pas être réutilisé dans un calcul. Pour réutiliser la valeur, il faut return.
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.
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).
| 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.