Les fonctions
Voici des instructions qui permettent d'afficher le carré d'un nombre
>>>a=3
>>>b=a**2
>>>b
9
Si, nous avons également besoin du carré de 5 et 7...
on pourrait copier-coller les instructions précédentes et afficher le résultat. Mais il y a mieux à faire : regrouper ces instructions dans un bloc
sous la forme d'une fonction, a devenant un paramètre de la fonction.
Une fonction permet donc d'éviter d'avoir à écrire plusieurs fois
le même code lorsqu'un même traitement doit être
mis en oeuvre à plusieurs endroits dans le programme.
En Python une fonction est définie par l'instruction composée def suivie du nom de la fonction et se termine obligatoirement par deux points :
puis le bloc d'instructions qu'il ne faut pas oublier d'indenter.
Une fonction est utilisée comme une instruction quelconque. Dans le corps d'un programme, un appel de fonction est
constitué du nom de la fonction suivi de parenthèses
La notion de fonction en informatique relève du même concept qu'une fonction mathématique, c'est-à-dire qu'on définit une fonction
puis on l'applique à différentes valeurs.
# -*- coding: utf-8 -*-
def carree(a) :
"""
Fonction permettant de renvoyer le carré du nombre a qui est en paramètre
"""
return a**2 # renvoye l'image de a par la fonction carree
Pour écrire le programme ci-dessus dans la zone de Saisie de programme de EduPython, on clique sur Fichier, Nouveau puis Nouveau Module Python
comme l'indique la figure ci-dessous :
ou bien, on clique sur Nouveau Fichier, l'icônePython 3.4, puis Créer
comme l'indique la figure ci-dessous :
Une fois la fonction est définie dans la zone de Saisie de programme de EduPython, on ne doit pas oublier de l'enregistrer dans le dossier qui convient en lui donnant un nom :
Après l'enregistrement, pour utiliser cette fonction, on l'appelle par l'instruction carree(3)
en utilisant la console pour afficher le carré de 3
mais il ne faut pas oublier d'exécuter le programme en utilisant l'icône "flèche verte" avant d'utiliser la console,
sinon la fonction carree ne sera pas reconnue comme l'indique la figure ci-dessous :
Lorsqu'on définit la fonction carree()
, a
est appelé paramètre de la fonction.
Quant on appelle la fonction avec une valeur explicite pour a, comme dans carree(3)
, on dira plutôt que 3 est un argument de
la fonction.
En appelant la fonction carree()
d'argument 3, on obtient 9 :
>>> carree(3)
9
>>>
Quelques remarques.
-
La fonction est auto-documentée par un texte entre """ et """ (c'est ce que l'on appelle
le docstring de la fonction).
Le docstring d'une fonction permet de donner des informations sur la fonction, le lien entre les entrées et la sortie
(en d'autres termes, le rôle de la fonction).
Toutes vos fonctions devront commencer ainsi par un docstring.
- Quant on saisit dans la console, après l'exécution de la fonction, l'instruction
help(nom de la fonction)
,
python affiche le docstring de la fonction ce qui nous permet d'avoir des informations sur la fonction en cas d'oubli.
>>> help(carree)
Help on function carree in module __main__:
carree(x)
Fonction permettant de renvoyer le carré
du nombre x qui est en paramètre
>>>
La fonction se termine avec une instruction return. Ce qui suit le return est l'image des entrées par la fonction.
Dès que la fonction rencontre un return, elle renvoie ce qui suit le return et stoppe son exécution.
Un autre exemple.
On considère le programme suivant dressant la table du 8 :
n=8
for k in range(1,11) :
print( '{}*{} = {}'.format(n,k,n*k) )
qui affiche :
8*1 = 8
8*2 = 16
8*3 = 24
8*4 = 32
8*5 = 40
8*6 = 48
8*7 = 56
8*8 = 64
8*9 = 72
8*10 = 80
Si, dans le même programme, nous avons également besoin de la table du 9, du 7...
on pourrait copier-coller le code précédent. Mais il y a mieux à faire : nommer ce code en le transformant en fonction,
n devenant un paramètre de la fonction.
def table(n) : # fonction nommée table et présentant un paramètre : n
for k in range(1,11) :
print( '{}*{} = {}'.format(n,k,n*k) )
print() # pour laisser une ligne vide en fin de table
## ce qui suit constitue des appels à la fonction table. ##
## Lorsqu'on appelle une fonction pour la mettre en oeuvre, ##
## on donne une valeur explicite aux paramètres de la fonction. ##
table(8) # appel de la fonction table avec l'argument 8
table(7) # appel de la fonction table avec l'argument 7
L'affichage obtenu :
8*1 = 8
8*2 = 16
8*3 = 24
8*4 = 32
8*5 = 40
8*6 = 48
8*7 = 56
8*8 = 64
8*9 = 72
8*10 = 80
7*1 = 7
7*2 = 14
7*3 = 21
7*4 = 28
7*5 = 35
7*6 = 42
7*7 = 49
7*8 = 56
7*9 = 63
7*10 = 70
Une fonction peut présenter plusieurs paramètres.
Si l'on veut pouvoir par exemple afficher la table de 1*n à 12*n (au lieu de l'affichage de 1*n à 10*n), on
peut ajouter un paramètre marquant le dernier coefficient voulu.
def table(n, fin) : # fonction nommée table et présentant deux paramètres : n et fin
for k in range(1,fin+1) :
print( '{}*{} = {}'.format(n,k,n*k) )
print()
## appels : ##
table(8, 12)
table(7, 15)
Ce qui donne :
8*1 = 8
8*2 = 16
8*3 = 24
8*4 = 32
8*5 = 40
8*6 = 48
8*7 = 56
8*8 = 64
8*9 = 72
8*10 = 80
8*11 = 88
8*12 = 96
7*1 = 7
7*2 = 14
7*3 = 21
7*4 = 28
7*5 = 35
7*6 = 42
7*7 = 49
7*8 = 56
7*9 = 63
7*10 = 70
7*11 = 77
7*12 = 84
7*13 = 91
7*14 = 98
7*15 = 105
Image par une fonction
Les deux fonctions définies ci-dessus ne font pas correspondre d'image à n (ou au couple (n, fin) ).
Ces fonctions se contentent d'afficher à l'écran un message. Dans certains langages, on parle plutôt de procédure
que de fonction dans une telle situation.
A quoi ressemblerait une fonction faisant correspondre une image à l'entier n ?
Comme un message est avant tout une chaîne de caractères, on pourrait décider ici de ne pas afficher cette chaîne, mais d'en faire
l'image de n.
def table(n) :
ch='' # initialisation de ch à la chaîne vide
for k in range(1,11) :
ch+='{}*{} = {}'.format(n,k,n*k)+'\n'
return ch # ch sera l'image de n
## appels : ##
table(8)
Lancez ce programme. Que se passe-t-il ?
Rien. Ou plutôt rien de visible. A l'appel de la fonction par l'instruction table(8)
, la fonction table() est
exécutée avec la valeur 8 pour le paramètre n. Une chaîne de caractères correspondant à la table du 8 est donc calculée par la
machine. Mais comme nous demandons seulement que cette chaîne
soit calculée et pas qu'elle soit affichée, on ne voit rien à l'écran.
Si l'on veut afficher la table :
def table(n) :
"""
Fonction permettant de retourner la table de multiplication du nombre n qui est en paramètre
"""
ch='' # initialisation de ch à la chaîne vide
for k in range(1,11) :
ch+='{}*{} = {}'.format(n,k,n*k)+'\n'
return ch # ch sera l'image de n
table_du_8=table(8) # appel à la fonction
# et affectation
# de l'image de 8 par cette fonction
# à la variable table_du_8.
print(table_du_8) # table_du_8
# est une chaîne de caractères,
# on demande son affichage.
A propos de la remarque qui vient d'être faite
(Dès que la fonction rencontre un return, elle retourne ce qui suit le return et stoppe son exécution.)
Le rôle de découpe en petits programmes
Il nous est arrivé d’écrire des programmes contenant des instructions qui reviennent plusieurs fois parce qu’il
fallait faire plusieurs fois la même chose.
Voici un exemple de programme, présentant des répétitions, qui affiche les horaires du train partant de châlons en champagne :
print("Le train à destination de ", end=" ")
print("Paris ", end=" ")
print(" partira à ", end=" ")
print("10h16 ", end="")
print(" et arrivera à ", end=" ")
print(" 11h53 ", end=" ")
print()
print("-----------------------------------------------")
print()
print("Le train à destination de ", end=" ")
print("Reims ", end=" ")
print(" partira à ", end=" ")
print("8h41", end=" ")
print(" et arrivera à ", end=" ")
print(" 9h23", end=" ")
print()
print("-----------------------------------------------")
print()
print("Le train à destination de ", end=" ")
print("Saint Dizier ", end=" ")
print(" partira à ", end=" ")
print("10h35 ", end=" ")
print(" et arrivera à ", end=" ")
print(" 10h54 ", end=" ")
print()
print("-----------------------------------------------")
print()
print("Le train à destination de ", end=" ")
print("Epernay ", end=" ")
print(" partira à ", end=" ")
print("8h15", end=" ")
print(" et arrivera à ", end=" ")
print(" 8h31", end=" ")
print()
print("-----------------------------------------------")
print()
ce qui affiche
Le train à destination de Paris partira à 10h16 et arrivera à 11h53
-----------------------------------------------
Le train à destination de Reims partira à 8h41 et arrivera à 9h23
-----------------------------------------------
Le train à destination de Saint Dizier partira à 10h35 et arrivera à 10h54
-----------------------------------------------
Le train à destination de Epernay partira à 8h15 et arrivera à 8h31
-----------------------------------------------
Un rôle important des fonctions est de découper votre programme
en "petites unités logiques" faciles à comprendre.
L'usage des fonctions, par ce rôle, facilite la conception
d'un programme mais aussi sa relecture, sa réutilisation,
les corrections.
On va chercher à réécrire ce programme.
Pour rendre ce programme plus facile à comprendre, on va le découper en fonctions,
chacune des fonctions écrites devra
avoir un rôle spécifique dans l'objectif de la résolution de ce problème.
Première fonction :
Notre première fonction devra sauter une ligne, ensuite tirer un trait séparateur puis de nouveau sauter une ligne.
def tirerUnTrait () :
"""
Une fonction qui permet de tirer un trait séparateur
"""
print()
print("---------------------------------------------------------------")
print()
## La suite est une utilisation de la fonction ##
tirerUnTrait ()
On obtient :
---------------------------------------------------------------
Seconde fonction :
Notre second programme aura pour objectif d'afficher la destination d'un train, l'horaire
de départ et l'horaire d'arrivée d'un train.
def annoncerUnDepart(destination, horaireDepart, horaireArrivee) :
"""
Une fonction qui permet d'afficher la destination, l'horaire
de départ et l'horaire d'arrivée d'un train
"""
print("Le vol en direction de ", end = " ")
print(destination, end = " ")
print(" partira à ", end = " ")
print(horaireDepart, end = " ")
print(" et arrivera à ", end = " ")
print(horaireArrivee, end = " ")
Ou bien
def annoncerUnDepart(destination, horaireDepart, horaireArrivee) :
"""
Une fonction qui permet d'afficher la destination, l'horaire
de départ et l'horaire d'arrivée d'un train
"""
print("Le vol en direction de {} partira à {} et arrivera à {}\
".format(destination,horaireDepart,horaireArrivee))
Remarque
- Dans une fonction, on peut faire appel à une autre fonction. Elles doivent être dans un même fichier
(il existe toutefois des techniques, avec
import
, permettant d'écrire ces fonctions dans des fichiers séparés.)
par exemple avec from Nomfichier import *
où Nomfichier est le fichier avec l'extension py
contenant toutes les fonctions qu'on utilise dans un programme.
-
On commence à voir ici l'intérêt du découpage en fonctions : si l'on accepte que la première fonction
fait bien ce que son docstring affirme, cette deuxième fonction est facile à écrire, facile à comprendre.
Les fonctions permettent ainsi de "découper" les difficultés en plus petits problèmes plus faciles à résoudre.
- Ce découpage, nous l'avons signalé, facilite la maintenance d'un programme. Si nous nous apercevons par exemple que notre
première fonction contient un bug, nous pouvons la réécrire, la corriger. Mais si nous respectons la nature des entrées et des sorties,
cette réécriture de la première fonction n'entraînera aucune modification de la seconde fonction. Vous pouvez facilement imaginer
l'intérêt de cela sur un programme comportant plusieurs dizaines de fonctions.
Vous pourrez par exemple vérifier que si l'on modifie la première fonction de l'une des façons ci-dessous, la seconde fonction
fonctionnera en apparence exactement de la même façon.
Si on nomme fonctions.py le fichier en python contenant les deux fonctions écrites ci-dessus, voici un programme utilisant ces fonctions
from fonctions import *
#Programme principal
## utilisation de la fonction ##
annoncerUnDepart ("Reims","8h41", "9h23")
tirerUnTrait ()
annoncerUnDepart ("Paris","10h16", "11h53")
tirerUnTrait ()
annoncerUnDepart ("Saint-Dizier","10h35", "10h54")
tirerUnTrait ()
annoncerUnDepart ("Epernay","08h15", "08h31")
Affichage :
Le train à destination de Paris partira à 10h16 et arrivera à 11h53
-----------------------------------------------
Le train à destination de Reims partira à 8h41 et arrivera à 9h23
-----------------------------------------------
Le train à destination de Saint Dizier partira à 10h35 et arrivera à 10h54
-----------------------------------------------
Le train à destination de Epernay partira à 8h15 et arrivera à 8h31
-----------------------------------------------
Dans ce cours
on traîte un exemple plus approfondi avec plusieurs fonctions.
Fonction Lambda
Python nous permet de définir des mini-fonctions d’une ligne. Ces fonctions dites lambda
peuvent être employées partout
où une fonction est nécessaire.
Exemple
>>>def f(x) :
... return x**2
...
>>> f(3)
9
>>>
Voici une fonction lambda
qui fait la même chose que la fonction ordinaire précédente.
On remarque que la syntaxe est condensée, il n’y a pas de parenthèses autour de la liste d’arguments et le mot-clé return est manquant
(il est implicite, la fonction complète ne pouvant être qu’une seule expression)
cette fonction n'a pas de nom, mais on peut l'affecter à une variable pour l'appeler à travers cette variable.
>>>g = lambda x : x**2
>>> g(3)
9
>>>