Fonctions
1. Définir une fonction
Lors du développement d’un projet informatique, de nombreuses lignes de programme sont souvent nécessaires.
Pour clarifier le code et rendre sa compréhension, et donc sa correction, plus faciles, il est possible de le décomposer en plusieurs sous-programmes plus simples qui peuvent être étudiés séparément.
D’autre part, il arrivera souvent qu’une même séquence d’instructions doive être utilisée à plusieurs reprises dans un programme, et on souhaitera bien évidemment ne pas avoir à la reproduire systématiquement.
Pour cela, nous pouvons définir de nouvelles fonctions, c’est-à-dire donner un nom à un groupe d’instructions, qui pourra être appelé à plusieurs reprises dans le programme principal. Cela revient à définir de nouvelles instructions.
En python, la syntaxe est la suivante :
def ma_fonction(liste des arguments de la fonction) :
...
# groupe d'instructions
...Remarquez les deux points et l’indentation. La première ligne, introduite par def est l’entête ou la signature de la fonction.
Voici un premier exemple de fonction qui prend en paramètre un nombre entier \(n\) :
def table(n) :
for k in range(11) :
print(n, "fois", k, "font", n * k)Pour exécuter cette fonction, il suffit d’écrire par exemple table(4) et on obtient l’affichage suivant :
4 fois 0 font 0
4 fois 1 font 4
4 fois 2 font 8
4 fois 3 font 12
4 fois 4 font 16
4 fois 5 font 20
4 fois 6 font 24
4 fois 7 font 28
4 fois 8 font 32
4 fois 9 font 36
4 fois 10 font 40Une fonction peut avoir plusieurs paramètres. Ils doivent alors être séparés par des virgules.
Par exemple, la fonction ci-dessous affiche le prix TTC en fonction du prix hors taxes et du taux de la taxe, donné en pourcentage :
def prixTTC(prixHT, taux) :
print(prixHT*(1+taux/100))On a souvent besoin de définir une fonction qui calcule une valeur ou qui retourne le résultat d’un algorithme. Il faut alors utiliser l’instruction return suivie du nom de la variable contenant la valeur à retourner.
# definition d'une fonction
def aire_triangle(base, hauteur) :
aire = base * hauteur / 2
return aire
# programme principal
a = aire_triangle(2, 3)
print(a)Remarque : Python propose des fonctions prêtes à être utilisées par le programmeur : les fonctions natives (built-in functions en anglais). Nous avons déjà eu l’occasion d’en voir deux avec type (qui renvoie le type d’une variable) et str qui renvoie la chaîne de caractère obtenue à partir d’un nombre (str(4) renvoie le caractère “4”). Il existe beaucoup d’autres fonctions natives Python (il en existe plus de 50). Nous pouvons en citer deux autres :
la fonction
lenprend en paramètre une chaîne de caractères et renvoie le nombre de caractères présents dans cette chaîne de caractères (par exemplelen("azerty")renvoie 5)la fonction
printpermet d’afficher à l’écran la valeur qui lui est passée en paramètre.
Dans ce qui précède, nous avons utilisé le terme fonction de manière très générale. Nous devons différencier deux types de “fonctions”.
- un groupe d’instruction qui retourne une valeur au programme principal est appelé une fonction. Une fonction ne réalise pas d’affichage : elle communique avec le programme principal par ses arguments et la valeur retournée.
- un groupe d’instruction qui ne retourne pas de valeur et qui peut éventuellement effectuer des affichages sera appelé une procédure.
Par exemple, le script ci-dessus qui affiche une table de multiplication et celui qui est nommé prixTTC sont des procédures. Par contre, aire_triangle est une fonction.
2. Utilisation de bibliothèques
Il est possible d’utiliser d’autres fonctions “prêtes à l’emploi” en important des bibliothèques, aussi appelées modules. Un module est un fichier contenant des fonctions qui pourront être utilisées dans d’autres programmes.
De nombreuses bibliothèques sont fournies avec une installation standard de Python, d’autres doivent être installées séparément.
Le module math est un module très important puisqu’il comporte toutes les fonctions mathématiques classiques : cosinus, sinus, exposant, racine carrée…
Pour utiliser les fonctions présentes dans un module, il est nécessaire d’importer le module dans notre programme. Par exemple, pour pouvoir utiliser les fonctions du module math il faudra écrire :
import mathau début de son programme.
Pour utiliser une fonction d’un module importé, il faudra préciser le nom du module qui propose cette fonction. Par exemple, pour déterminer le sinus de 3.14, il faudra écrire :
math.sin(3.14)Voici une série de calculs qui fait appel à des fonctions issues du module maths :
import math
a = 5
b = 16
c = 3.14
puis = math.pow(a,3)
racine = math.sqrt(b)
s = math.sin(c)Après l’exécution de ce programme :
- la variable
puisaura pour valeur \(5^3 = 125\) ; - la variable
racineaura pour valeur \(\sqrt{16}=4\) : - la variable
saura pour valeur \(\sin(3.14)\approx 0.05\).
Pour alléger l’écriture, on peut aussi importer toutes les fonctions du module directement dans notre programme en tapant : from math import *. Il n’est alors plus nécessaire de spécifier math. devant chaque fonction utilisée.
Parmi les modules que nous utiliserons pour débuter se trouvent :
- le module
mathdéjà cité ; - le module
randomintroduisant des fonctions permettant de générer des nombres aléatoires ;
| Fonction | Effet |
|---|---|
randrange(a,b) |
renvoie un entier aléatoire dans \([a;b[\) |
randint(a,b) |
renvoie un entier aléatoire dans \([a;b]\) |
random() |
renvoie un flottant aléatoire dans \([0;1[\) |
uniform(a,b) |
renvoie un flottant aléatoire dans \([a;b]\) |
- le module
turtleest une implémentation en Python du langage Logo créé dans les années 1970 pour l’enseignement de l’informatique à l’école. Il est disponible dans la distribution standard de Python. En déplaçant une pointe de stylo qui peut être matérialisée par une tortue, on peut tracer des figures géométriques dans un repère cartésien dont l’origine est au centre de la fenêtre et dont l’unité par défaut est le pixel. Lorsqu’on déplace le crayon, il laisse une trace s’il est baissé ou pas de trace s’il est levé. Nous utiliserons les fonctions suivantes de turtle :
| Fonction | Effet |
|---|---|
| goto(x,y) | déplace la tortue jusqu’au point de coordonnées (x, y) |
| penup() | lever le crayon |
| pendown() | baisser le crayon |
| setheading(angle) | choisir l’angle d’orientation de la tortue en degrés |
| forward(n) | avancer de n pixels selon l’orientation de la tortue |
| left(a) | tourne à gauche de a degrés |
| right(a) | tourne à droite de a degrés |
| color(“red”) | choisir la couleur rouge (ou “black”, “green”, “blue” . . . ) |
Pour connaître toutes les fonctions contenues dans une bibliothèque, on peut, après avoir tapé import math dans la console interactive, taper ensuite help(math). On peut aussi consulter la documentation officielle.
Voici par exemple un programme qui génère la figure ci-dessous :
import turtle as tt
def spirale(n):
tt.penup()
tt.goto(0,0)
tt.pendown()
c = 5
for i in range(4):
for j in range(4):
tt.forward(c)
c = 10 + c
tt.left(90)
spirale(4)
tt.exitonclick()Quelques remarques complémentaires sur ce programme :
- à la ligne 1, on importe le module
turtleen le renommantttafin d’alléger l’appel aux fonctions de cette bibliothèque. Cette pratique est très courante. - à la ligne 14, la fonction
exitonclick()permet de fermer la fenêtre graphique en cliquant une fois à l’intérieur.
Il est aussi possible de créer un module personnel, regroupant toutes les fonctions que vous avez créées pour un projet particulier.
Supposons par exemple que nous avons créé un fichier MesFonc.py dans lequel nous avons mis les définitions des fonctions fonc1 et fonc2.
Pour réutiliser ces fonctions dans un autre programme, on pourra importer le module MesFonc en tapant :
from MesFonc import *: import de toutes les fonctions du module, utilisables sans préfixe.from MesFonc import fonc1: import uniquement de la fonctionfonc1, utilisable sans préfixe.import MesFonc: import de toutes les fonctions du module, utilisables avec préfixe. Pour appeler la fonctionfonc1, on taperaMesFonc.fonc1().import MesFonc as MF: import de toutes les fonctions du module, utilisables avec préfixe alias, par commodité. Pour appeler la fonctionfonc1, on taperaMF.fonc1().
Les deux dernières possibilités sont intéressantes, par exemple, lorsqu’une fonction du module a le même nom qu’une autre fonction Python.
3. Variables locales et variables globales
Considérons le programme suivant :
def ma_fonc():
i = 5
ma_fonc()
print (i)Nous commençons par définir une fonction ma_fonc qui ne prend aucun paramètre et qui ne renvoie aucune valeur (absence du mot-clef return). Cette fonction attribue juste la valeur 5 à la variable ayant pour nom i.
À la 3e ligne du programme, nous exécutons la fonction ma_fonc.
Rappelons que la fonction print permet d’afficher à l’écran la valeur qui lui est passée en paramètre. La 4e ligne de ce programme permet donc d’afficher la valeur de la variable i à l’écran.
On pourrait penser que ce programme va donc afficher 5 ! Pas du tout, nous avons le droit à l’erreur suivante :
NameError: name 'i' is not definedLe message d’erreur est suffisamment parlant, inutile de s’attarder dessus : la variable i n’est pas définie. À noter que cette erreur est déclenchée par la 4e ligne (le print).
Pourquoi cette erreur, la variable i est bien définie dans la fonction ma_fonc et la fonction ma_fonc est bien exécutée, où est donc le problème ?
En fait, la variable i est une variable dite locale : elle a été définie dans une fonction et elle “restera” dans cette fonction. Une fois que l’exécution de la fonction sera terminée, la variable i sera “détruite” (supprimée de la mémoire). Elle n’est donc pas accessible depuis “l’extérieur” de la fonction (ce qui explique le message d’erreur que nous obtenons, car le print est en dehors la fonction ma_fonc, la variable i n’est donc plus accessible).
Étudions maintenant un cas un peu plus complexe :
i = 3
def ma_fonc():
i = 5
ma_fonc()
print (i) On pourrait s’attendre à voir s’afficher la valeur 5 à l’écran. Pas du tout, nous ne rencontrons pas d’erreur cette fois, mais c’est la valeur 3 qui s’affiche à l’écran.
En fait dans cet exemple, nous avons 2 variables i différentes : la variable i “globale” (celle qui a été définie en dehors de toute fonction) et la variable i “locale” (celle qui a été définie dans la fonction). Ces 2 variables portent le même nom, mais sont différentes (elles correspondent à des cases mémoire différentes). Au moment de l’exécution du print à la 5e ligne seule la variable globale existe encore (celle définie à la première ligne du programme), d’où l’affichage du 3.
Une variable globale peut être “utilisée” à l’intérieur d’une fonction :
i = 3
def ma_fonc():
print (i)
ma_fonc()Attention, le print se situe dans la fonction (la ligne du print est bien indentée)
Ce programme permet d’afficher la valeur 3 à l’écran.
Quand on cherche à utiliser une variable dans une fonction, le système va d’abord chercher si cette variable se “trouve” dans l’espace local de la fonction, puis, s’il ne la trouve pas dans cet espace local, le système va aller rechercher la variable dans l’espace global. Pour le print(i) situé dans la fonction le système ne trouve pas de variable i dans l’espace local de la fonction ma_fonc, il passe donc à l’espace global et trouve la variable i (nous avons donc 3 qui s’affiche).
Il est important de bien comprendre que dans le programme ci-dessous le système trouve une variable i dans l’espace local de la fonction, la “recherche” de la variable i se serait arrêtée là :
i = 3
def ma_fonc():
i = 5
print (i)
ma_fonc()et ce programme affiche la valeur 5 à l’écran. i a été trouvée dans l’espace local de la fonction ma_fonc, la recherche ne va donc pas plus loin (inutile de remonter jusqu’à l’espace global)
En revanche le programme ci-dessous génère une erreur : “UnboundLocalError: local variable ‘i’ referenced before assignment”
i = 3
def ma_fonc():
i = i + 1
ma_fonc()
print(i)Il n’est à priori pas possible de modifier une variable globale (ici la variable i) dans une fonction.
Pour pouvoir modifier une variable globale dans une fonction, il faut le déclarer explicitement en utilisant le mot-clef global :
i = 3
def ma_fonc():
global i
i = i + 1
ma_fonc()
print(i)Ici, aucune erreur la valeur 4 est bien affichée à l’écran.
Il est fortement déconseillé de donner le même nom à une variable locale et à une variable globale pour éviter ce genre de confusions.
On évitera également l’emploi du mot-clef global car cette utilisation peut entraîner des “effets de bord”.
Lorsqu’on écrit un programme, python crée un espace de noms (namespace) dans lequel les noms des variables et des fonctions définies dans ce programme sont stockés.
À l’intérieur de chaque fonction, il est possible de définir aussi des variables. Un nouvel espace de noms, complètement indépendant de l’espace de noms principal est créé pour chaque fonction.
Par conséquent, une variable définie à l’intérieur d’une fonction n’est pas accessible depuis le programme principal et elle n’existe plus lorsque l’exécution de la fonction est terminée (même si elle porte le même nom qu’une variable du programme principal). On dit qu’il s’agit d’une variable locale.
On parle d’effet de bord quand une fonction modifie l’état d’une variable globale. Dans notre exemple ci-dessus, la fonction ma_fonc modifie bien la valeur de i : avant l’exécution de ma_fonc, i a la valeur 3, après l’exécution de la fonction ma_fonc, i est associé à la valeur 4. Nous avons donc bien un effet de bord.
Les effets de bords provoquent parfois des comportements non désirés par le programmeur (évidemment dans des programmes très complexes, pas dans des cas simplistes comme celui que nous venons de voir). Ils rendent aussi parfois les programmes difficilement lisibles (difficilement compréhensibles). À cause des effets de bord, on risque de se retrouver avec des variables qui auront des valeurs qui n’étaient pas prévues par le programmeur. On dit aussi qu’à un instant donné, l’état futur des variables est difficilement prévisible à cause des effets de bord. En résumé, on évitera autant que possible l’utilisation du “global”.
