Un cap pour ce chapitre
Ce que vous saurez faire
- Expliquer un appel de fonction et son résultat
- Distinguer paramètres locaux et variables de l’appelant
- Différencier print et return
Les bases utiles pour commencer
Définir n’est pas exécuter
L’instruction def définit une fonction ; son corps s’exécute lorsqu’un appel est effectué. Dans def double(x), x est un paramètre, c’est-à-dire un nom utilisé à l’intérieur pour recevoir une donnée. Dans double(7), 7 est l’argument fourni. Pour expliquer un appel, commencez par associer les arguments aux paramètres dans leur ordre, puis suivez le corps avec ces valeurs. Une fonction peut être appelée plusieurs fois avec des arguments différents sans recopier son algorithme. Le nom choisi devrait annoncer le service rendu, par exemple distance ou nombre_occurrences.
Pour deux paramètres, l’ordre des arguments compte : une fonction de soustraction appelée avec trois puis huit ne reçoit pas les mêmes données qu’avec huit puis trois. Écrivez une petite table « paramètre / argument reçu » avant de tracer un appel comportant plusieurs données.
Renvoyer permet de poursuivre le calcul
return fournit un résultat à l’endroit de l’appel et termine immédiatement l’exécution de la fonction. print affiche une représentation et sert à communiquer avec l’utilisateur ; il ne remplace pas un résultat utilisable dans une expression. Une fonction qui atteint sa fin sans return renvoie None. On peut donc afficher 14 dans une fonction et pourtant ne pas pouvoir additionner son résultat à 1. Pour construire des programmes composables, les fonctions de calcul renvoient généralement leurs résultats, et l’affichage est organisé par le programme qui les appelle.
Une instruction située après un retour sur le même chemin n’est jamais exécutée. Inversement, un affichage ne termine pas la fonction : les instructions suivantes se poursuivent. Le résultat retourné peut être stocké, comparé ou transmis directement à un nouvel appel.
Chaque appel possède ses noms locaux
Les paramètres et les variables créées dans une fonction sont locaux à son exécution. Dans une fonction qui reçoit x puis exécute x = x + 2, l’affectation change le nom local x. Pour un argument entier, elle ne remplace pas la variable utilisée par l’appelant. Cette distinction évite de compter sur une modification qui n’aura pas lieu. Nous limitons ici les exemples aux nombres ; les objets modifiables demandent ensuite de distinguer réaffectation d’un nom et modification d’un objet partagé.
def augmente(x):
x = x + 2
return x
score = 5
nouveau = augmente(score)
print(score, nouveau)Deux appels successifs ne partagent pas leurs variables locales ordinaires. Le deuxième appel recommence avec ses nouveaux arguments. Pour conserver un résultat entre les appels, le programme extérieur doit le récupérer explicitement puis le retransmettre, au lieu de supposer une mémoire cachée dans le paramètre.
Composer et traiter tous les chemins
Une fonction peut utiliser le résultat d’une autre : double(augmente(5)) appelle d’abord augmente(5), puis transmet son résultat à double. Les parenthèses organisent cette composition. Dans une fonction conditionnelle, il faut vérifier tous les chemins pour respecter le résultat annoncé. Si un return existe seulement dans le cas x > 0, le cas x = 0 peut renvoyer involontairement None. Une spécification simple, quelques cas limites et une trace des appels permettent de repérer cette omission avant qu’elle se manifeste loin de la fonction responsable.
La composition n’est généralement pas commutative. Sur une seule entrée, deux ordres peuvent cependant coïncider : avec zéro, les deux expressions de l’atelier donnent un. Ce cas particulier ne prouve pas leur équivalence pour les autres entiers.
Décomposer un prix en services simples
Une fonction prix_ligne(quantite, prix_unitaire) peut renvoyer leur produit. Une autre total_commande(prix_a, prix_b, livraison) peut additionner trois montants. Pour deux articles à sept euros, trois articles à quatre euros et une livraison de cinq euros, les prix de lignes sont quatorze et douze ; le total est trente et un. Chaque appel a un contrat court et un résultat vérifiable.
La livraison n’est pas ajoutée dans chaque prix de ligne, sinon elle serait facturée deux fois. La décomposition doit suivre le sens des données. Le programme principal peut afficher le total une fois le calcul terminé, ce qui permet aussi de réutiliser les fonctions dans une autre interface.
Tous les chemins doivent tenir la même promesse
Une fonction qui indique le plus grand de deux nombres peut renvoyer le premier si celui-ci est supérieur ou égal au second, puis renvoyer le second dans l’autre cas. L’égalité est ainsi traitée explicitement. Si l’on utilise deux comparaisons strictes et aucun retour supplémentaire, les arguments égaux provoquent un retour implicite de None.
Pour vérifier une fonction conditionnelle, dessinez ses branches puis associez une entrée à chaque chemin : premier plus grand, second plus grand, égalité. Vérifiez aussi le type du résultat. Une branche renvoyant un nombre et une autre un message textuel compliquent les calculs suivants, sauf si cette diversité fait explicitement partie du contrat.
À vous de faire varier les choses
Deux fonctions, deux ordres
Choisissez une entrée et l’ordre de composition. Suivez les résultats intermédiaires sans modifier la valeur de départ.
Lire le résultat de l’expérience initiale
Résultat renvoyé : 16
Le x extérieur reste 3. Chaque appel reçoit son propre paramètre et renvoie une valeur à l’appel suivant.
| Appel | Argument | Résultat renvoyé |
|---|---|---|
| ajoute_un | 3 | 4 |
| carre | 4 | 16 |
Lire les appels de l’intérieur vers l’extérieur permet de reconstruire la circulation des valeurs.
De la compréhension à l’autonomie
À vous de résoudre
Cherchez d’abord par vous-même. Vérifiez les résultats demandés, utilisez les indices si nécessaire, puis comparez votre méthode à la correction.
Deux noms semblables
Une fonction calcule x = x + 4 puis renvoie x. Le programme fait x = 3 et y = fonction(x). Donnez x et y à la fin.
Indice 1
Distinguez le nom local x du nom extérieur x.
Indice 2
La fonction reçoit la valeur 3, puis renvoie 7.
Comprendre la correction
Le x extérieur reste 3 et y reçoit 7. L’affectation du corps agit sur le nom local de l’appel. La valeur retournée peut ensuite être affectée à une variable extérieure, mais ce choix appartient à l’appelant. Écrire x = fonction(x) aurait, cette fois, remplacé le x extérieur par 7.
Afficher ne suffit pas
La fonction double(x) contient seulement print(2 * x). Pourquoi y = double(6) ne donne-t-il pas y = 12 ? Comment corriger pour calculer ensuite y + 1 ?
Indice 1
Observez séparément ce qui apparaît à l’écran et ce qui est renvoyé.
Indice 2
Une fonction sans return explicite renvoie None.
Comprendre la correction
L’écran affiche 12, mais y reçoit None. L’expression y + 1 échoue alors. Il faut remplacer le corps par return 2 * x ; y devient 12 et y + 1 vaut 13. On peut ajouter print(y) à l’extérieur si l’on souhaite aussi montrer le résultat.
Un chemin sans résultat
Une fonction signe(x) renvoie 1 si x > 0 et -1 si x < 0. Que manque-t-il pour respecter le contrat « renvoyer -1, 0 ou 1 » ?
Indice 1
Examinez une entrée qui ne satisfait aucune des deux conditions.
Indice 2
Zéro est un cas valide, pas une erreur à ignorer.
Comprendre la correction
Il manque le cas x == 0, pour lequel il faut renvoyer 0. Sans ce retour, l’exécution atteint la fin et produit None. On peut utiliser if, elif puis else, chaque branche contenant un return. Le contrat aide ici à reconnaître une omission même sans message d’erreur immédiat.
Comprendre une composition
On définit ajoute_un(x) qui renvoie x + 1 et carre(x) qui renvoie x * x. Comparez carre(ajoute_un(3)) et ajoute_un(carre(3)).
Indice 1
Calculez d’abord l’appel placé le plus à l’intérieur.
Indice 2
L’ordre des transformations peut modifier le résultat.
Comprendre la correction
carre(ajoute_un(3)) calcule d’abord 4, puis 4 × 4 : le résultat est 16. ajoute_un(carre(3)) calcule d’abord 9, puis ajoute un : le résultat est 10. Les mêmes fonctions sont utilisées, mais leur ordre de composition change le traitement et donc la réponse.
Trois appels pour une commande
Une fonction ligne(q, p) renvoie q * p. Une fonction total(a, b, port) renvoie la somme des trois paramètres. Calculez total(ligne(4, 3), ligne(2, 8), 5) en détaillant les retours. Indiquez où placer l’affichage.
Indice 1
Les appels intérieurs fournissent les arguments du dernier appel.
Indice 2
Le port est ajouté une seule fois.
Comprendre la correction
Les prix de lignes sont douze et seize. Le dernier appel reçoit donc 12, 16 et 5, puis renvoie 33. Un affichage extérieur peut montrer cette valeur sans changer les fonctions de calcul. Si ligne affichait simplement ses produits, les arguments reçus seraient None et l’addition ne fonctionnerait pas.
Un retour avant la fin
Une fonction renvoie x + 1 si x > 0, puis renvoie 0 dans tous les autres cas. Une instruction d’affichage est placée après ce second retour. Donnez les résultats pour -2, 0 et 4, puis expliquez combien de fois l’affichage est atteint.
Indice 1
Chaque retour interrompt l’appel.
Indice 2
Suivez séparément le chemin positif et le chemin non positif.
Comprendre la correction
Pour -2 et zéro, le premier test est faux et le second retour donne zéro. Pour quatre, le premier retour donne cinq et termine déjà l’appel. L’affichage placé après le dernier retour n’est atteint sur aucun chemin. Il faudrait le placer avant le retour concerné, ou afficher le résultat à l’extérieur.
Le compteur qui ne change pas
La fonction suivant(n) renvoie n + 1. Un programme initialise n = 5, appelle deux fois suivant(n) sans affectation, puis calcule r = suivant(suivant(n)). Donnez n et r. Corrigez les deux appels ignorés pour faire augmenter durablement n.
Indice 1
Une valeur retournée peut être ignorée.
Indice 2
Le nom extérieur change seulement si une instruction le réaffecte.
Comprendre la correction
Les deux premiers retours, égaux à six, sont ignorés. Le nom extérieur reste cinq. La composition calcule ensuite six puis sept : r vaut sept. Pour deux augmentations durables, il faut écrire deux fois n = suivant(n). Le premier appel part alors de cinq et le second de six.
Les erreurs qui méritent un détour
- Penser que
defexécute immédiatement le corps - Repérez les appels effectifs : une fonction définie mais jamais appelée ne réalise pas son traitement.
- Utiliser une variable locale après l’appel
- Transmettez explicitement l’information utile avec
returnplutôt que de dépendre d’un nom interne.
La fiche à garder
L’essentiel à retenir
- Un appel associe arguments et paramètres.
return transmet un résultat ; printaffiche.- Les variables locales appartiennent à l’exécution de la fonction.
Le prochain pas
Retrouver le catalogue de Première
Ce chapitre s’appuie sur le programme officiel de Première (PDF, nouvel onglet). Les explications et exercices sont proposés pour l’apprentissage.
