Fonctions#
Qu'est-ce qu'une fonction ?#
Dans un programme, certains blocs d'instructions doivent être réutilisés à plusieurs endroits. On peut par exemple imaginer une dizaine d'instructions permettant de vérifier qu'un mot de passe est suffisamment robuste (au moins 12 caractères, une majuscule, un caractère spécial, etc.). Ces instructions devront non seulement être utilisées lors de l'inscription d'un nouvel utilisateur, mais également lors du changement de mot de passe.
On pourrait simplement copier/coller ces dix lignes à ces deux endroits du programme. Dès lors, le programme pourrait être représenté avec le schéma ci-dessous, dans lequel les cases bleues représentent le même code dupliqué à deux endroits différents.
Toutefois, recopier les mêmes instructions plusieurs fois vient avec des désavantages
Si le code doit être modifié, il faudra aller le changer partout où il a été copié/collé
Du point de vue d'un programmeur qui découvre le code, il n'est pas clair au 1er coup d'oeil que ces lignes copiées/collées sont les mêmes et qu'elles doivent le rester
Pour ce même programmeur, l'utilité de ces lignes n'est pas directement claire non plus : il devra les lire pour les analyser et les comprendre.
Pour pallier ces problèmes, le code utilisé 2x ne doit pas être copié/collé, mais déplacé "en marge" du programme principal dans une fonction. Lorsque, dans notre programme, on souhaite utiliser ces instructions mises en marge, on ne fait alors qu'un appel à cette fonction. Le programme ressemblera dès lors à cela :
Avec cela, lorsqu'on modifie une fois le code à réutiliser, la modification impactera tous les appels de fonction. De plus, le nom de la fonction (ici F) devrait être significatif et nommer l'action effectuée par la fonction. Dans l'exemple de la vérification de sécurité du mot de passe, la fonction aurait pu avoir comme nom vérifie_sécurité_mdp. Ainsi, avec une fonction, le programme devient plus lisible et est plus facilement modifiable.
Définir et appeler une fonction#
Le mot-clef permettant de définir une fonction est def. Celui-ci est suivi du nom de la fonction puis d'une paire de parenthèses et de deux-points. Les instructions indentées sous la définition constituent le corps de la fonction, c'est-à-dire le bloc d'instructions à exécuter lorsque la fonction est appelée.
Définir une fonction ne l'exécute pas : il faut encore l'appeler, en écrivant son nom suivi d'une paire de parenthèses. Dans l'exemple ci-dessous, la fonction affiche_salutations est définie une seule fois, puis appelée 2x à différents endroits du programme.
1def affiche_salutations():
2 print("Bonjour")
3 print("Comment allez-vous ?")
4
5print("Début du programme")
6affiche_salutations()
7print("Pouvez-vous répéter svp, je n'ai pas compris")
8affiche_salutations()
Fonction avec paramètres#
Les fonctions peuvent être paramétrées. C'est-à-dire que leur exécution va dépendre de valeurs qui seront précisées au moment de l'appel. Ces paramètres se placent entre les parenthèses de la définition de la fonction et sont séparés par une virgule. Ils peuvent ensuite être réutilisés dans le corps de la fonction. Lors de l'appel, on précise obligatoirement les valeurs des paramètres entre les parenthèses.
1def calcul_et_affiche_aire_triangle(base, hauteur):
2 aire = base * hauteur / 2
3 print("L'aire d'un triangle de", base, "de base et", hauteur, "de hauteur est de", aire)
4
5calcul_et_affiche_aire_triangle(10, 20)
6calcul_et_affiche_aire_triangle(20, 10)
7calcul_et_affiche_aire_triangle(35, 54)
Afficher n'est pas retourner#
La fonction ci-dessus affiche son résultat avec un print. Le problème, c'est que les valeurs affichées sont ensuite perdues : impossible de les additionner pour obtenir l'aire totale, de les comparer, ou de les réutiliser plus loin. La fonction a montré le résultat à l'écran, mais elle ne l'a pas donné au programme.
Avec le mot-clef return, la fonction rend sa valeur au programme au lieu de simplement l'afficher. On peut alors la récupérer dans une variable et l'utiliser à notre guise, par exemple pour additionner deux aires.
1def aire_triangle(base, hauteur):
2 aire = base * hauteur / 2
3 return aire
4
5aire1 = aire_triangle(5, 10)
6aire2 = aire_triangle(10, 13)
7
8aire_totale = aire1 + aire2
9print("Aire totale :", aire_totale)
Important
printaffiche une valeur à l'écran. On la voit, mais le programme ne peut pas la réutiliser.returnrend une valeur au programme. Rien ne s'affiche, mais on peut la récupérer et la réutiliser.
Récupérer et utiliser une valeur de retour#
Une valeur retournée n'est utile que si on la récupère. Dans le programme ci-dessous, la fonction calcule bien le double de 5, mais comme le résultat n'est rangé nulle part, il est immédiatement perdu : le programme n'affiche donc rien du tout.
1def double(nombre):
2 return nombre * 2
3
4double(5) # la valeur 10 est calculée... puis jetée
Pour utiliser la valeur retournée, il faut la capter en la plaçant après une variable et un =, exactement comme on le fait avec un input(). Plus généralement, l'appel d'une fonction qui retourne une valeur peut s'utiliser partout où l'on pourrait écrire cette valeur : dans une variable, directement dans un print, dans un calcul ou dans une condition.
1def double(nombre):
2 return nombre * 2
3
4resultat = double(5) # ranger le résultat dans une variable
5print(resultat)
6print(double(5)) # afficher directement le résultat
7total = double(5) + double(10) # utiliser le résultat dans un calcul
8print("Total :", total)
9
10if double(5) > 8: # utiliser le résultat dans une condition
11 print("Le double de 5 est plus grand que 8")
Avertissement
C'est l'erreur la plus fréquente avec les fonctions : écrire double(5) en pensant que "ça va
afficher 10". Une fonction qui return n'affiche jamais rien toute seule. Si vous voulez
voir la valeur, il faut soit la ranger dans une variable, soit l'afficher vous-même avec un
print.
Le return met fin à la fonction#
Dès qu'un return est exécuté, la fonction s'arrête immédiatement : les instructions qui le suivent dans le corps de la fonction ne sont jamais exécutées. Dans l'exemple ci-dessous, si le nombre est positif, le premier return renvoie sa valeur et quitte la fonction ; le second return n'est atteint que pour les nombres négatifs. On n'a donc même pas besoin d'un else.
1def valeur_absolue(nombre):
2 if nombre >= 0:
3 return nombre
4 return -nombre
5
6print(valeur_absolue(7))
7print(valeur_absolue(-4))
Exercices#
Exercice 22#
Définir une fonction et l'appeler sont deux choses différentes, et les lignes d'un programme ne s'exécutent plus forcément de haut en bas. Lisez attentivement le programme ci-dessous et répondez sans l'exécuter.
1def bonjour():
2 print("B")
3 print("C")
4
5print("A")
6bonjour()
7print("D")
8bonjour()
9print("E")
Dans quel ordre les lettres s'affichent-elles ? Écrivez-les à la suite, sans espaces.
Quelle est la première ligne exécutée par le programme ?
Combien de fois la ligne 3 est-elle exécutée ?
Combien de fois la ligne 5 est-elle exécutée ?
Solution
La réponse est ABCDBCE.
Les lignes 1 à 3 ne font que définir la fonction : elles ne s'exécutent pas au moment où
Python les lit. La première ligne réellement exécutée est donc la ligne 5, qui affiche A.
Arrivé à la ligne 6, Python saute dans le corps de la fonction, exécute les lignes 2 et 3
(B puis C), revient à la ligne 6, puis continue avec la ligne 7 (D). Le deuxième appel,
ligne 8, refait exactement le même détour : B puis C à nouveau. Enfin la ligne 9 affiche E.
Les lignes 2 et 3 s'exécutent donc deux fois chacune, alors qu'elles ne sont écrites qu'une seule fois : c'est précisément l'intérêt d'une fonction.
Exercice 23#
Les cinq programmes ci-dessous se ressemblent, mais n'affichent pas la même chose. Pour chacun,
prédisez ce qui s'affiche à l'écran, en réfléchissant à ce que fait vraiment chaque appel de
fonction. Si le programme n'affiche rien, écrivez rien.
def double(nombre): return nombre * 2 double(5) print("Terminé")
def double(nombre): return nombre * 2 resultat = double(5) print(resultat)
def double(nombre): print(nombre * 2) double(5)
def double(nombre): return nombre * 2 print(double(5) + double(10))
def prix_total(quantite): return quantite * 3 commande = prix_total(4) print(commande + 5)
Solution
Terminéseulement. La fonction calcule bien10, mais comme cet appeldouble(5)n'est rangé dans aucune variable, la valeur est aussitôt perdue. La seule chose affichée est leprint("Terminé")de la dernière ligne. C'est le piège n° 1 des fonctions : unreturnn'affiche rien tout seul.10. Cette fois l'appel est capté dans la variableresultat, que leprintaffiche ensuite.10également, mais pour une raison opposée au programme 2 ! Ici la fonction ne retourne rien : c'est elle-même qui contient leprint. Le résultat s'affiche donc pendant l'appel. Les programmes 2 et 3 affichent la même chose, mais dans le programme 3 on ne pourrait pas réutiliser la valeur10ailleurs, alors que dans le programme 2, oui.30. Un appel qui retourne une valeur peut s'utiliser directement dans un calcul :double(5)vaut 10,double(10)vaut 20, et c'est leur somme qui est affichée.17. L'appelprix_total(4)retourne12, qui est rangé danscommande. La dernière ligne affiche donccommande + 5, soit17.
Exercice 24#
Chacun des programmes suivants comporte au moins une erreur. Parfois, cette erreur fait directement buguer le programme avec un message d'erreur rouge. D'autres fois, le programme s'exécute correctement, mais son résultat n'est pas logique.
Corrigez chacun de ces codes de manière à ce qu'ils s'exécutent correctement et affichent un résultat logique.
1def périmètre_carré(côté): 2 périmètre = côté * 4 3 print(périmètre) 4 5p1 = périmètre_carré(5) 6p2 = périmètre_carré(7) 7total = p1 + p2 8print(total)
1def maximum(liste): 2 maximum = -99999 3 for n in liste: 4 if n > maximum: 5 maximum = n 6 return maximum 7 8#Doit afficher le maximum de la liste ci-dessous 9ma_liste = [4, 6, 2, 8, -4, 3, 10, 9, 4, 7, -3] 10maximum(ma_liste)
1def applique_réduction(prix, code): 2 if code == "STX": 3 return prix * 0.8 4 elif code == "JANM": 5 return prix * 0.65 6 elif code == "FRI": 7 return prix * 0.9 8 else: 9 return prix 10 11prix_de_base_1 = 67 12prix_de_base_2 = 45 13applique_réduction(prix_de_base_1, "JANM") 14applique_réduction(prix_de_base_2, "STX") 15prix_réduit_total = prix_de_base_1 + prix_de_base_2 16print(prix_réduit_total)
1def ajoute_s(mot, nombre): 2 if nombre > 1: 3 mot + "s" 4 else: 5 mot 6 7n_chat = int(input("Combien de chats as-tu ?")) 8n_chien = int(input("Combien de chiens as-tu ?")) 9txt_chat = ajoute_s("chat", n_chat) 10txt_chien = ajoute_s("chien", n_chien) 11print("Tu as", n_chat, txt_chat, "et", n_chien, txt_chien)
Solution
1def périmètre_carré(côté): 2 périmètre = côté * 4 3 return périmètre 4 5p1 = périmètre_carré(5) 6p2 = périmètre_carré(7) 7total = p1 + p2 8print(total)
Avec un
print, la fonction affiche le périmètre mais ne le rend pas :p1etp2ne contiennent alors rien (None) et l'addition plante. Il faut unreturn.1def maximum(liste): 2 maximum = -99999 3 for n in liste: 4 if n > maximum: 5 maximum = n 6 return maximum 7 8#Doit afficher le maximum de la liste ci-dessous 9ma_liste = [4, 6, 2, 8, -4, 3, 10, 9, 4, 7, -3] 10m = maximum(ma_liste) 11print(m)
La fonction est correcte, mais sa valeur de retour n'est ni récupérée ni affichée.
1def applique_réduction(prix, code): 2 if code == "STX": 3 return prix * 0.8 4 elif code == "JANM": 5 return prix * 0.65 6 elif code == "FRI": 7 return prix * 0.9 8 else: 9 return prix 10 11prix_de_base_1 = 67 12prix_de_base_2 = 45 13réduit_1 = applique_réduction(prix_de_base_1, "JANM") 14réduit_2 = applique_réduction(prix_de_base_2, "STX") 15prix_réduit_total = réduit_1 + réduit_2 16print(prix_réduit_total)
Appeler la fonction ne modifie pas les variables
prix_de_base_1etprix_de_base_2: les prix réduits sont retournés, il faut donc les récupérer dans de nouvelles variables.1def ajoute_s(mot, nombre): 2 if nombre > 1: 3 return mot + "s" 4 else: 5 return mot 6 7n_chat = int(input("Combien de chats as-tu ?")) 8n_chien = int(input("Combien de chiens as-tu ?")) 9txt_chat = ajoute_s("chat", n_chat) 10txt_chien = ajoute_s("chien", n_chien) 11print("Tu as", n_chat, txt_chat, "et", n_chien, txt_chien)
Calculer
mot + "s"ne suffit pas : sansreturn, ce texte est calculé puis perdu.
Exercice 25#
Définissez une fonction nommée sanctions_STX permettant de déterminer les sanctions à STX en fonction du nombre de retards et du nombre d'absences injustifiées. Pour rappel, les sanctions sont les suivantes :
Au moins 3 retards ou 2 absences injustifiées :
retenueAu moins 6 retards ou 4 absences injustifiées :
retenue samedi matinAu moins 9 retards ou 6 absences injustifiées :
avertissement écritAu moins 12 retards ou 8 absences injustifiées :
menace d'exclusionAu moins 15 retards ou 10 absences injustifiées :
exclusionEn dessous de tout cela :
rien
La fonction retourne la sanction. Utilisez-la ensuite pour déterminer les sanctions de 2 élèves : l'un ayant 4 retards et 0 absence injustifiée, l'autre 2 retards et 2 absences injustifiées.
Si les deux sanctions sont pareilles, votre programme affichera en plus : Deux mêmes sanctions...
1def sanctions_STX(n_retards, n_absences_inj):
Solution
1def sanctions_STX(n_retards, n_absences_inj):
2 if n_retards >= 15 or n_absences_inj >= 10:
3 return "exclusion"
4 elif n_retards >= 12 or n_absences_inj >= 8:
5 return "menace d'exclusion"
6 elif n_retards >= 9 or n_absences_inj >= 6:
7 return "avertissement écrit"
8 elif n_retards >= 6 or n_absences_inj >= 4:
9 return "retenue samedi matin"
10 elif n_retards >= 3 or n_absences_inj >= 2:
11 return "retenue"
12 else:
13 return "rien"
14
15sanction1 = sanctions_STX(4, 0)
16sanction2 = sanctions_STX(2, 2)
17print("Sanction du 1er élève :", sanction1)
18print("Sanction du 2ème élève :", sanction2)
19if sanction1 == sanction2:
20 print("Deux mêmes sanctions...")
Les conditions sont testées de la sanction la plus grave à la moins grave : comme un return
met fin à la fonction, dès qu'une condition est vraie, les suivantes ne sont plus testées. Dans
l'ordre inverse, un élève avec 15 retards recevrait une simple retenue.
Exercice 26#
Une fonction devient vraiment utile lorsqu'on la réutilise sur des données différentes. Écrivez
une fonction moyenne qui reçoit une liste de nombres en paramètre et qui retourne leur
moyenne. Utilisez-la ensuite, sans la réécrire, pour afficher successivement le prix moyen des
pizzas d'une carte et la température moyenne de la semaine.
1def moyenne(liste):
2 # Complétez le corps de la fonction
3
4prix_pizzas = [12.5, 18, 22.5, 15, 19]
5températures = [14, 17, 21, 19, 12, 9, 13]
6
7# Appelez la fonction deux fois et affichez les deux résultats
Solution
1def moyenne(liste):
2 total = 0
3 for valeur in liste:
4 total = total + valeur
5 return total / len(liste)
6
7prix_pizzas = [12.5, 18, 22.5, 15, 19]
8températures = [14, 17, 21, 19, 12, 9, 13]
9
10print("Prix moyen d'une pizza :", moyenne(prix_pizzas), "CHF")
11print("Température moyenne de la semaine :", moyenne(températures), "°C")
Le prix moyen est de 17.4 CHF et la température moyenne de 15 °C.
Remarquez que la fonction ne sait rien des pizzas ni de la météo : elle reçoit une liste de nombres et rend leur moyenne, un point c'est tout. C'est ce qui permet de l'appeler deux fois sur des données qui n'ont aucun rapport entre elles.