Les fonctions
On doit calculer une moyenne à cinq endroits du programme. Va-t-on recopier le calcul cinq fois ? Le jour où la formule change, il faudra retrouver les cinq copies, et on en oublieras une.
Une fonction est un morceau de programme qui porte un nom. On l'écrit une fois, on l'appelle autant qu'on veut. C'est l'outil qui transforme un long script illisible en briques que l'on comprend séparément, et c'est la base de tout travail à plusieurs.
Ce qu'on va apprendre
- Définir une fonction avec
def, et l'appeler. - Lui donner des paramètres et récupérer un résultat avec
return. - Ne plus confondre afficher et renvoyer, la confusion la plus coûteuse du chapitre.
- Comprendre pourquoi une fonction ne voit pas le reste du programme, et pourquoi elle peut quand même modifier une liste.
- Écrire des fonctions qu'on relit sans effort.
Définir, puis appeler
Une fonction est un bloc d'instructions nommé. On la définit avec def, un nom, des parenthèses et deux points ; son corps est indenté. On l'appelle en écrivant son nom suivi de parenthèses.
def ne fait rien s'exécuter : il dessine le plan et range la fonction sous son nom. C'est l'appel, avec les parenthèses, qui construit la maison.Deux conséquences qu'on vérifiera en modifiant le bloc ci-dessus. Retire les deux appels : plus rien ne s'affiche, bien que la fonction soit parfaitement définie. Écrire
saluer sans parenthèses : rien ne se passe non plus, on a simplement désigné la fonction sans la lancer.
Les paramètres : ce qui entre
Un paramètre est une information que la fonction reçoit pour travailler dessus. On le nomme entre les parenthèses de la définition, et l'on donne sa valeur, l'argument, au moment de l'appel.
nom, quoi qu'il arrive. Le nom de la variable qu'on envoie depuis l'extérieur n'a aucun rapport avec lui, et n'a pas besoin de lui ressembler.C'est ce qui rend une fonction réutilisable : elle se moque de ce qui se passe dehors.
La valeur de retour : ce qui sort
return renvoie un résultat à celui qui a appelé la fonction, et arrête son exécution sur-le-champ.
print a l'air de marcher. Le résultat s'affiche, on est content. Il n'existe pourtant nulle part dans le programme, et le jour où l'on veut s'en resservir, tout casse.print parle à l'humain qui regarde l'écran. return donne la valeur au programme.
Le bloc suivant est faux exprès : la fonction affiche au lieu de renvoyer.
40 s'affiche bien, puis TypeError: unsupported operand type(s) for *: 'NoneType' and 'float'.
Une fonction sans return renvoie None, qui signifie « rien ». prix_remise vaut donc None, et multiplier « rien » par 1,2 n'a pas de sens.
À faire. Remplace print(nouveau_prix) par return nouveau_prix et relance. Le calcul aboutit, mais plus rien ne s'affiche au milieu : c'est normal, c'est l'appelant qui décide maintenant quoi faire du résultat.
Renvoyer plusieurs valeurs
Une fonction peut renvoyer plusieurs choses d'un coup. Python les regroupe, et l'on peut les récupérer séparément.
Les valeurs par défaut
Un paramètre peut avoir une valeur employée quand l'appel n'en fournit pas.
Nommer les arguments à l'appel devient indispensable dès qu'une fonction en prend quatre ou cinq : tracer(donnees, couleur="rouge", epaisseur=2) se relit, tracer(donnees, "rouge", 2) beaucoup moins.
La portée : une fonction est une bulle
Une variable créée dans une fonction est locale : elle naît à l'appel, meurt au retour, et n'existe pas ailleurs. Une variable définie en dehors est globale : la fonction peut la lire, mais lui affecter une valeur crée en réalité une locale du même nom.
Le bloc suivant est faux exprès : il tente de lire une locale depuis l'extérieur.
NameError: name 'resultat' is not defined. La variable a existé le temps de l'appel, puis a disparu. Pour la faire sortir, il n'y a qu'un moyen : return.
Une bonne fonction reçoit tout ce dont elle a besoin par ses paramètres et rend son résultat par return. On peut alors la lire seule, la tester seule, la déplacer ailleurs.
Le cas des listes
Souvenons-nous du chapitre 2 : une variable est une étiquette collée sur une valeur. Quand on passe une liste à une fonction, on ne passes pas une copie : on passe l'étiquette. La fonction en colle une seconde sur la même liste.
Ce n'est ni un bug ni une exception : c'est la conséquence directe de l'étiquette. Mais c'est une surprise le jour où l'on découvre que sa liste a été vidée par une fonction appelée trois lignes plus haut.
En cas de doute, travaille sur une copie :
notes = notes.copy() en première ligne de la fonction, et rends le résultat par return.
Les règles d'or d'une bonne fonction
Une seule chose. Si on ne peut pas dire ce que fait la fonction en une phrase sans « et », c'est qu'il y en a deux.
Un nom qui dit le résultat. calculer_moyenne vaut mieux que traiter. Une fonction qui renvoie un booléen se nomme volontiers est_pair, contient, peut_ouvrir.
Tout par les paramètres. Ce dont elle a besoin entre par la porte, pas par une globale.
Un résultat par return. L'affichage appartient à celui qui appelle, pas à elle. Une fonction qui calcule et affiche est deux fois moins réutilisable.
Courte. Au-delà d'une vingtaine de lignes, il y a presque toujours une deuxième fonction cachée dedans.
Documenter avec une docstring
Un texte entre triples guillemets, juste après le def, dit ce que fait la fonction. C'est ce que renvoie help(), et ce que l'éditeur affichera quand on la réutiliseras dans six mois.
Une bonne docstring dit ce que la fonction renvoie, pas comment elle s'y prend : le comment est déjà dans le code, juste en dessous.
1.Une fonction contient print(x * 2) mais aucun return. Que vaut resultat après resultat = f(5) ?
2.Quelle différence entre un paramètre et un argument ?
3.Une fonction a un paramètre nommé valeur. Comment doit s'appeler la variable qu'on lui passe ?
4.Une fonction fait notes.append(20) sur la liste qu'on lui passe, sans return. La liste d'origine est-elle modifiée ?
5.Que fait return au milieu d'une fonction ?
À mettre en pratique
La mention. Écrire mention(note) qui renvoie la mention d'une note sur 20 : « Très bien » à partir de 16, « Bien » à partir de 14, « Passable » à partir de 10, sinon « Insuffisant ».
Afficher la solution
Deux points valent qu'on s'y arrête.
La fonction renvoie au lieu d'afficher. C'est ce qui permet d'écrire if mention(note) == "Tres bien": ailleurs dans le programme, ce qu'une version avec print interdirait.
Le dernier cas n'a pas besoin de else : si l'on est arrivé jusque-là, c'est qu'aucun return précédent ne s'est déclenché. Les deux écritures sont correctes, celle-ci est un peu plus plate à lire.
Synthèse
defdéfinit, les parenthèses appellent. Définir sans appeler ne fait rien.- Les paramètres sont l'entrée,
returnla sortie. - Le nom d'un paramètre est local : il n'a aucun lien avec la variable passée à l'appel.
- Afficher n'est pas renvoyer. Sans
return, une fonction renvoieNone. returnarrête la fonction sur-le-champ.- Une variable créée dans une fonction est locale et disparaît au retour.
- Une fonction peut modifier une liste qu'on lui passe : c'est la même liste, pas une copie.
- Une bonne fonction fait une seule chose, reçoit tout par ses paramètres, et rend par
return.
Mettre en pratique
Paramètres, valeur de retour et réutilisation.
- Paramètre par défaut2 · Fonctions
- Suivre un appel de fonction2 · Fonctions
- Une fonction qui salue2 · Fonctions
- Test de positivité2 · Fonctions
- Le plus petit de deux nombres2 · Fonctions
- Maximum de trois nombres3 · Confirmé
- Divisibilité2 · Fonctions
- Un paramètre par défaut2 · Fonctions
- Prix après réduction2 · Fonctions
- Retourner plusieurs valeurs3 · Confirmé
- Débogage : la moyenne est fausse3 · Confirmé