Chapitre 1.7 - Fonctions (Généralités)
I. Les fonctions en Python⚓︎
Notion de fonction⚓︎
Les fonctions
En informatique, les fonctions servent à mieux structurer votre code. On dit aussi que les fonctions servent à factoriser le code. Elles permettent d'éviter de répéter plusieurs fois des portions de codes identiques. Ainsi, une fonction peut être vue comme un «petit» programme :
- à qui on donne des paramètres en entrée,
- puis qui effectue alors un traitement sur ces paramètres, dans le corps de la fonction.
- qui renvoie enfin un résultat en sortie.
Une fonction qui modifie des variables mais sans renvoyer de résultat est appellée une procédure. Le langage Python ne fait pas de différence dans la syntaxe entre fonction et procédure.
Syntaxe en Python⚓︎
En Python, une fonction peut s'écrire en suivant toujours le même formalisme :
Syntaxe
- Le mot clé
def
+ nom de la fonction + les paramètres entre parenthèses (pour chacun un nom de variable). + Terminer par deux points:
- Si la fonction ne prend aucun paramètres, on met quand même les parenthèses sans rien à l'intérieur.
- En dessous, écrire le blocs des instructions. Attention il faut indenter (décaler) ce bloc.
- Si la fonction renvoie un résultat, finir en dernière ligne par le mot clé
return
suivi de ce que renvoie la fonction. Attention, cette ligne est indentée également et marque la fin de la fonction.
Visuellement cela donne quelque chose comme ceci:
return
Dès que l'instruction return
est exécutée, on "sort" de la fonction.
Un return
dans une boucle provoque donc une sortie anticipée de la boucle.
🌵 Il ne faut pas l'oublier ...
Appeler (utiliser) une fonction En Python⚓︎
Appel de fonction
Lorsque l'on définit une fonction, on ajoute une fonctionalité à python, mais la fonction n'est pas exécutée. Elle ne le sera que lorsque l'on va appeler cette fonction.
Une fonction est utilisée comme une instruction quelconque. Un appel de fonction est constitué du nom de la fonction suivi entre parenthèses des valeurs des paramètres d'entrée. Cet appel peut être fait :
- Soit, comme nous l'avons vu, dans le programme principal (ou dans une autre fonction)
def double(nombre) :
return 2*nombre
a = 5
reponse = double(a) # La fonction est appelée ici
print("le double de ", a,"vaut :", reponse)
- Soit par un appel en console :
Vocabulaire :⚓︎
paramètre et argument
Lorsqu'on écrit double(nombre)
, nombre
est appelé paramètre de la fonction double
.
Lorsqu'on appelle la fonction double
avec une valeur explicite pour nombre
comme dans double(6)
, on dit que 6
est un argument de la fonction double
.
Ainsi, si on appelle la fonction double
avec l'argument 5, celle-ci renvoie 10
.
II. Portée des variables⚓︎
Suivre ce lien, et bien l'étudier :
III. Assertions⚓︎
Tester - 1
Exécuter le script ci-dessous :
Que s'est-il passé ?
Il ne se passe rien, le assert
a bien été vérifié.
Tester - 2
Exécuter le script ci-dessous :
# Tests
(insensible à la casse)(Ctrl+I)
Que s'est-il passé ?
😢 On a une erreur : assertion erreur.
Le message de l'erreur est celui que nous avons indiqué sur la ligne assert
assert
👉assert
est souvent utilisé pour signaler qu’il y a une erreur dans le code de la fonction.
👉 Lorsque l'on crée une fonction, on crée en même temps un "jeu de tests" que l'on vérifiera avec des assert
Tester - 3
Corrigeons notre fonction. Tester ci-dessous :
# Tests
(insensible à la casse)(Ctrl+I)
Que s'est-il passé ?
On constate que tous les tests se sont bien passés.
🐘 A retenir
A partie de maintenant, vous écrirez toujours les assert avant de réaliser le code de votre fonction.
😊 C'est ainsi que l'on doit mettre au point un programme
Remarque
🌵 Souvent, on n'écrit pas de message dans l'assertion.
Voir ci-dessous.
À vous de jouer
Compléter la fonction suivante qui calcule la somme \(1+2+...+n\)
Ajouter un jeu de tests avec des assert
(Les messages ne sont pas obligatoires)
# Tests
(insensible à la casse)(Ctrl+I)
IV. Exercices⚓︎
Exercice 1 : promotions
🎁 Dans une parfumerie, on propose deux promotions différentes pour l'achat de deux articles :
- Formule A : une réduction de 50% sur le prix du 2ème article (le moins cher)
- Formule B : une réduction de 20% sur le montant total à payer.
Muni d'un billet de 50€, Nicolas souhaite offrir deux parfums à sa mère .
1. Ecrire une fonction promo_A
qui prend en paramètres prix1
et prix2
et qui renvoie le prix total à payer pour l’achat de deux parfums aux prix prix1
et prix2
.
Par exemple :
promo_A(10, 20)
doit renvoyer25
, etpromo_A(20, 10)
doit également renvoyer25
.
Compléter ci-dessous. Il faut exécuter votre code, et ensuite obligatoirement le valider () pour voir la solution.
# Tests
(insensible à la casse)(Ctrl+I)
ENCRYPTION_TOKEN
Solution
ENCRYPTION_TOKEN
2. Ecrire de même, une fonction promo_B
.
Par exemple :
promoB(10, 20)
doit renvoyer 24promoB(20, 10)
doit également renvoyer 24.
Compléter ci-dessous.
# Tests
(insensible à la casse)(Ctrl+I)
ENCRYPTION_TOKEN
Solution
ENCRYPTION_TOKEN
3. Ajouter le programme principal :
Il doit demander la saisie du prix des deux parfums, afficher le prix avec la formule A et la formule B, Afficher quelle est la formule la plus avantageuse, et si Nicolas pourra offrir les deux parfums à sa mère (il ne dispose que de 50 euros).
Vous testerez votre code pour :
- Un parfum à 10 € et un autre à 20 €
- Un parfum à 12 € et un autre à 45 €
- Un parfum à 35 € et un autre à 20 €
Les fonctions promo_A
et promo_B
sont dans du code caché. Il est inutile de les écrire.
# Tests
(insensible à la casse)(Ctrl+I)
Solution
prix_1 = float(input("prix_1 = "))
prix_2 = float(input("prix_2 = "))
prix_final_A = promo_A(prix_1, prix_2)
prix_final_B = promo_B(prix_1, prix_2)
print("le prix final a payer avec la promotion A est de : ", prix_final_A, "euros")
print("le prix final a payer avec la promotion B est de : ", prix_final_B, "euros")
if prix_final_A < prix_final_B:
print("la promotion A est plus avantageuse que que la promotion B")
prix_final = prix_final_A
elif prix_final_A == prix_final_B:
print("les deux promotions donnent des prix identiques")
prix_final = prix_final_A
else:
print("la promotion B est plus avantageuse que que la promotion A")
prix_final = prix_final_B
if prix_final > 50:
print("Nicolas ne peut pas acheter, il n a que 50 euros")
Utilisation de la tortue
# Tests
(insensible à la casse)(Ctrl+I)
Exercice 2 : Des triangles avec la tortue
1. Tester ci-dessous
# Tests
(insensible à la casse)(Ctrl+I)
2. Compléter ci-dessous pour qu'il s'affiche :
Contrainte
Il est interdit de modifier la fonction.
Il faudra l'appeler plusieurs fois.
# Tests
(insensible à la casse)(Ctrl+I)
Solution
3. Question facultative : Compléter ci-dessous pour qu'il s'affiche :
Contrainte
Il est interdit de modifier la fonction.
Il faudra l'appeler plusieurs fois.
# Tests
(insensible à la casse)(Ctrl+I)
Solution
- Si votre figure correspond à ce que vous avez demandé, c'est que c'est juste. 👍
- Sinon, réfléchissez encore ! 😅 Cette question est facultative ...
Exercice 3 : Des maximums
1. Ecrire une fonction maxi_2
qui prend en paramètre deux nombres entiers n1
et n2
et renvoie le plus grand des deux.
# Tests
(insensible à la casse)(Ctrl+I)
ENCRYPTION_TOKEN
Solution
ENCRYPTION_TOKEN
2. Ecrire une fonction maxi_3
qui prend en paramètre trois nombres entiers n1
, n2
et n3
et renvoie le plus grand des trois.
Contrainte
Vous appelerez obligatoirement la fonction maxi_2
# Tests
(insensible à la casse)(Ctrl+I)
Exercice 4 : Des voyelles
1. Recopier, une à une les instructions ci-dessous dans la console, et observer le résultat
Tester ci-dessous :
# Tests
(insensible à la casse)(Ctrl+I)
2. Compléter la fonction suivante qui renvoie le nombre de voyelles dans mot
.
Vous pourrez utiliser les syntaxes vues au 1.
# Tests
(insensible à la casse)(Ctrl+I)
Exercice 5 : La suite de Syracuse
La conjecture de Syracuse (ou de Collatz) postule ceci :
Prenons un nombre \(n\) :
- si \(n\) est pair, on le divise par 2
- sinon on le multiplie par 3 puis on ajoute 1.
On recommence cette opération tant que possible. Au bout d'un certain temps, on finira toujours par tomber sur le nombre 1.
1. Compléter la fonction suivant
qui prend en paramètre un entier n
et renvoie son successeur en respectant les règles énoncées ci-dessus.
# Tests
(insensible à la casse)(Ctrl+I)
ENCRYPTION_TOKEN
Solution
ENCRYPTION_TOKEN
2. Écrire une fonction syracuse
qui prend en paramètre un entier n
et qui affiche tous les termes de la suite de Syracuse jusqu'à 1 (on l'espère !).
Vous appelerez obligatoirement la fonction du 1.
# Tests
(insensible à la casse)(Ctrl+I)
3. Écrire une fonction temps_de_vol
qui prend en paramètre un entier n
et qui renvoie le nombre d'étapes pour arriver à 1, en partant de n
.
Par exemple temps_de_vol(5)
doit renvoyer 5.
# Tests
(insensible à la casse)(Ctrl+I)
ENCRYPTION_TOKEN
Solution
ENCRYPTION_TOKEN
4. Compléter la fonction suivante pour afficher le nombre de départ inférieur ou égal à n
donnant le plus grand temps de vol, ainsi que le temps de vol correspondant . Vous pourrez uppeler les fonctions écrites aux questions précédentes.
# Tests
(insensible à la casse)(Ctrl+I)
V. Bilan⚓︎
Exemple
Définition d'une fonction
La 1ère ligne de la fonction est la définition de la fonction :
Elle commence par le mot clef def, suivie du nom de la fonction, puis entre parenthèse, les paramètres de la fonction.Elle se termine par : qui indique qu'en dessous va se trouver un bloc d'instructions.
Paramètres d'une fonction
Dans def prix(nbre_adultes, nbre_enfants)
, on dit que nbre_adultes
et nbre_enfants
sont des paramètres de la fonction.
Ce sont des variables dont les valeurs seront déterminées lors de l'appel de la fonction.
def prix(nbre_adultes, nbre_enfants):
resultat = 37 * nbre_adultes + 28 * nbre_enfants # (1)
return resultat
- 👉 Remarque importante : Cette ligne utilise les variables
nbre_adultes
etnbre_enfants
qui ne sont pas initialisée dans la fonction. C'est normal, comme nous l'avons dit juste au-dessus, ces variables seront initialisées lors de l'appel de la fonction.
Prenez le temps de lire les commentaires (cliquez sur le +)
Corps de la fonction
def prix(nbre_adultes, nbre_enfants):
resultat = 37 * nbre_adultes + 28 * nbre_enfants
return resultat # (1)
return
signifie renvoyer, c'est cette ligne qui indique ce que va renvoyer la fonction. Ici elle renvoie resultat, donc elle renvoie la valeur de la variable resultat
Prenez le temps de lire les commentaires (cliquez sur le +)
Appel de la fonction
Cette ligne de code ne fait pas partie de la fonction (Elle n'est pas dans le bloc indenté). Les lignes de codes qui ne sont pas dans une fonction font partie de ce qu'on appelle le programme principal.
Une fois qu'une fonction est définie, il est possible de l'appeler (l'utiliser) dans le programme principal, mais aussi dans une autre fonction.
Utiliser le résultat renvoyé par une fonction
Toutefois, l'appel ci-dessus ne fait qu'appeler la fonction, qui renvoie le résultat. Ceci ne sera pas utile si nous ne conservons pas ce résultat (afin de pouvoir l'utiliser dans la suite du programme). Pour cela nous allons en général affecter ce résultat à une variable :
Si on veut seulement afficher le résultat, on peut directement afficher ainsi :
Arguments de la fonction
Quand on « appelle » prix(3, 2)
:
• 3 est automatiquement affecté au 1er paramètre : la variable nbre_adultes
• 2 est automatiquement affecté au second paramètre : la variable nbre_enfants
3 et 2 sont les valeurs données en arguments.
Remarque 1 :⚓︎
Une fonction sans paramètres
Certaines fonctions n'ont aucun paramètre. Dans ce cas, on met des parenthèses vides aussi bien dans la définition que dans l'appel de la fonction :
Remarque 2 :⚓︎
Des fonctions qui ne renvoient rien
Certaines fonctions ne renvoient rien.
Exemple :
def ma_fonction(nom) :
print("Votre nom est :",nom)
return None # ou simplement return, ou pas de return du tout ...
ma_fonction()
De telles fonctions sont, dans certains langages, appelées des procédures. En python, on ne fait pas de différence. Une procédure fait quelques chose : ici par exemple, elle sert à afficher (dans la console) un message.
Notez que dans l'appel d'une procédure, on n'affecte pas le résultat à une variable. C'est logique car il n'y a pas de résultat, puisque la fonction ne renvoie rien.
Notion d'espace de noms⚓︎
Portée des variables
Une variable définie dans une fonction n'est connue qu'à l'"intérieur" de celle-ci.
Par exemple si on exécute ceci:
def prix(nbre_adultes, nbre_enfants):
resultat = 37 * nbre_adultes + 28 * nbre_enfants
return resultat
prix(resultat) # Cette ligne provoquera un message d'erreur !
On obtient le message :
En effet, la variable resultat
n'est connue qu'à l'"intérieur" de la fonction
Définitions
- Les variables définies dans le corps d'une fonction sont appelées variables locales.
- Les variables définies dans le corps du programme (sous-entendu : pas à l'intérieur d'une fonction) sont appelées variables globales.
Règles d'accès aux variables locales et globales
- règle 1 : une variable locale (définie au cœur d'une fonction) est inaccessible hors de cette fonction.
- règle 2 : une variable globale (définie à l'extérieur d'une fonction) est accessible en lecture à l'intérieur d'une fonction.
- règle 3 : une variable globale (définie à l'extérieur d'une fonction) ne peut pas être modifiée à l'intérieur d'une fonction.
Source : Gilles Lassus
Tester les variables locales et globales - 1
Exécuter le code ci-dessous, et comprendre le message d'erreur :
# Tests
(insensible à la casse)(Ctrl+I)
Tester les variables locales et globales - 2
Exécuter le code ci-dessous, et comprendre ce qui se passe :
# Tests
(insensible à la casse)(Ctrl+I)
Testez vos fonctions
-
Choisir un cas ou vous pouvez, sans l'aide du code, déterminer ce que la fonction doit renvoyer.
-
Ajouter l'instruction assert
Exemple d'utilisation pour une fonction carre
qui élève au carré:
Si le test est réussi, il ne se passera rien, sinon le code lève une exception AssertionError et affiche le message.
👉 Remarque : souvent nous n'écrirons pas de message explicatif. Nous nous contenterons par exemple de :
Dans ce cas-là, si le test est réussi, il ne se passera rien, sinon le code lève une exception AssertionError et n'affiche pas de message.
Une fonction peut appeler une autre fonction
Toutes nos fonctions (que nous écrivons ou que nous importons) sont définies avant toute exécution du programme. De sorte que, lorsque l'exécution du code commence, elles sont toutes reconnues et utilisables en tout point du code, y compris dans d'autres fonctions.
# Tests
(insensible à la casse)(Ctrl+I)