Les fonctions
Ce que ce chapitre apporte 5 points
- 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 parcours.
- Comprendre pourquoi une variable créée dans une fonction n'existe pas au dehors.
- Écrire une fonction complète, avec des conditions et plusieurs return.
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 oubliera 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 chapitre installe la mécanique en quatre temps : définir et appeler une fonction, lui faire entrer des valeurs, en faire sortir une, et comprendre ce qu'elle voit du reste du programme. Il suffit pour cela des variables, des conditions et des boucles. Le reste, les valeurs par défaut, plusieurs valeurs renvoyées d'un coup, global et les listes passées à une fonction, est rangé à part, en fin de chapitre.
Le chapitre suivant, bien écrire une fonction, reprend la même fonction et la rend relisable, vérifiable et réutilisable par d'autres.
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. Retirer 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.
Un programme définit une fonction saluer() avec def, mais ne l'appelle nulle part. Qu'affiche-t-il ?
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.
Ce que « définir » et « appeler » veulent dire se voit mieux qu'il ne se raconte. La trace ci-dessous déroule un programme ligne par ligne : la ligne surlignée est celle qui vient de s'exécuter, et le panneau de droite donne l'état des variables à cet instant.
| 1 | def saluer(qui): |
| 2 | message = "Bonjour " + qui |
| 3 | print(message) |
| 4 | |
| 5 | saluer("Alice") |
| 6 | saluer("Bob") |
Variables
Aucune variable n'existe encore.
def s'exécute et aucune variable n'apparaît : le plan est rangé, rien n'est construit. Au pas suivant, la ligne de l'appel s'allume et un cadre « dans saluer() » surgit, portant déjà qui : les arguments sont liés avant que la première ligne du corps ne s'exécute. message s'y ajoute au pas d'après. Au retour, ce cadre disparaît entièrement : ni qui ni message n'ont laissé la moindre trace dans les variables globales. Le second appel recrée un cadre neuf, avec une autre valeur de qui.
Quelle différence entre un paramètre et un argument ?
Le nom du paramètre ne regarde que la fonction. À l'intérieur, la donnée s'appellera 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.
Une fonction a un paramètre nommé valeur. Comment doit s'appeler la variable qu'on lui passe ?
Une fonction peut recevoir plusieurs paramètres : on les sépare par des virgules, et les arguments se donnent dans le même ordre. La section suivante en montre une, addition(a, b).
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.
Un appel qui renvoie une valeur s'emploie partout où l'on écrirait cette valeur : dans un calcul, dans un print, et même comme argument d'un autre appel.
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.
Les deux versions, côte à côte dans la même trace, rendent la différence visible : la première affiche et remonte None, la seconde ne montre rien et remonte une valeur.
| 1 | def version_print(prix): |
| 2 | print(prix - 10) |
| 3 | |
| 4 | def version_return(prix): |
| 5 | return prix - 10 |
| 6 | |
| 7 | affichee = version_print(50) |
| 8 | rendue = version_return(50) |
Variables
Aucune variable n'existe encore.
Le tableau des variables tranche ce que la sortie ne dit pas : 40 s'affiche dans les deux cas, mais une seule des deux variables contient quelque chose d'utilisable.
À faire. Dans le bloc faux exprès, remplacer print(nouveau_prix) par return nouveau_prix, puis relancer. 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.
Une fonction contient print(x * 2) mais aucun return. Que vaut resultat après resultat = f(5) ?
return arrête la fonction sur-le-champ. Une fonction peut donc en contenir plusieurs, un par cas, et seul le premier atteint s'exécute.
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.
Pour aller plus loin
Rien de ce qui suit n'est nécessaire pour écrire ses premières fonctions. Ce sont des outils et des pièges qu'on rencontre ensuite, une fois la mécanique installée.
Ce que sont un paramètre, un argument et une valeur de retour se dit aussi indépendamment de Python, dans le chapitre d'algorithmique sur les fonctions et leurs paramètres, et le découpage d'un programme en fonctions y a son propre chapitre, la modularité. Sur deux points, Python est moins strict que le pseudo-code de ce parcours : une fonction y lit les variables du programme principal, on l'a vu avec taux, et une liste passée en paramètre n'y est pas recopiée, si bien que la fonction peut modifier celle de l'appelant.
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.
Renvoyer plusieurs valeurs
Une fonction peut renvoyer plusieurs choses d'un coup : on les sépare par des virgules après return, et l'on peut les récupérer séparément.
Python regroupe les deux valeurs en un tuple, que la ligne d'appel dépaquette en deux noms. Les tuples sont présentés au chapitre sur les structures de données.
Modifier une variable du programme : global
Lire une globale est fragile ; lui affecter une valeur depuis une fonction est impossible sans le dire. L'affectation crée une locale, comme l'a montré la section sur la portée, et si la fonction lit la variable avant de l'affecter, Python lève une UnboundLocalError. Le mot-clé global lève cette barrière : il annonce que le nom désigne la variable du programme principal, et non une locale.
Le chapitre sur MicroPython s'en sert une fois, pour simuler sur PC une broche qu'on lit bit par bit : la fonction lire() doit garder la forme de broche.value(), sans paramètre, et c'est la seule raison de ce choix. En temps normal, on s'en passe, et la version sans global ne coûte qu'un mot de plus à l'appel :
La fonction ne touche plus à rien au-dehors : elle reçoit l'ancienne valeur par un paramètre et rend la nouvelle par return. En lisant compteur = compter_piece(compteur), on voit que compteur change, ce que la version avec global cachait dans le corps de la fonction.
Une liste passée à une fonction
Une fonction fait notes.append(20) sur la liste qu'on lui passe, sans return. La liste d'origine est-elle modifiée ?
Rappel du chapitre 2 : une variable est une étiquette collée sur une valeur. Quand on passe une liste à une fonction, on ne passe pas une copie : on passe l'étiquette. La fonction en colle une seconde sur la même liste.
| 1 | def ajouter_bonus(v): |
| 2 | v.append(20) |
| 3 | |
| 4 | def remplacer(v): |
| 5 | v = [0] |
| 6 | |
| 7 | notes = [12, 15] |
| 8 | ajouter_bonus(notes) |
| 9 | remplacer(notes) |
| 10 | print(notes) |
Variables
Aucune variable n'existe encore.
notes dans les variables globales pendant les deux appels. Pendant le premier, le cadre affiche v avec la même liste que notes, et l'append change les deux d'un coup, puisqu'il n'y en a qu'une. Pendant le second, v = [0] ne change que v : la ligne a recollé l'étiquette du cadre sur une autre liste, sans toucher à celle de l'appelant. Toute la difficulté de cette section tient dans l'écart entre ces deux lignes.
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, travailler sur une copie :
notes = notes.copy() en première ligne de la fonction, et rendre le résultat par return.
Une valeur par défaut n'est calculée qu'une fois
def, pas à chaque appel. Si cette valeur est une liste, tous les appels qui n'en fournissent pas partagent la même, et celle-ci garde ce que les appels précédents y ont mis.
Aucune erreur n'est levée, et c'est bien ce qui rend le piège coûteux : le bloc affiche ['pain'], puis ['pain', 'lait'], puis ['pain', 'lait', 'oeufs']. Le deuxième appel, qui ne demandait qu'un panier neuf, reçoit les courses du premier.
La parade tient en deux lignes, et c'est la forme qu'on rencontre dans tout le code professionnel : la valeur par défaut est None, et la liste se crée dans la fonction, donc à chaque appel.
La règle courte : jamais de liste, de dictionnaire ni d'ensemble comme valeur par défaut. Un nombre, une chaîne ou un booléen ne posent pas ce problème, puisqu'on ne peut pas les modifier sur place.
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.
Les exercices du thème Fonctions sont rangés dans l'ordre où les faire : les neuf premiers ne demandent que ce qui précède.
Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?
Dans la bibliothèque d'exercices
Paramètres, valeur de retour et réutilisation.
- Suivre un appel de fonction2 · Fonctions
- Une variable locale2 · Fonctions
- Une fonction et son appel3 · Confirmé
- Compter les pièces conformes4 · Avancé
- Débogage : le total vaut None2 · Fonctions
- Débogage : la moyenne est fausse3 · Confirmé
- Le maillon le plus faible2 · Fonctions
- Les extrêmes d'une journée3 · Confirmé