Non, non, rassurez-vous, pas de maths ici ( quoique...), la notion de fonction en informatique est assez différente de celle utilisée en mathématiques.
Vous avez en fait déjà utilisé des fonctions ( print()
, input()
,...), mais à quoi exactement correspond cette notion ?
Certaines parties de programme peuvent ( ou doivent ) être parfois utilisées plusieurs fois; il est donc nécessaire de pouvoir les « appeler » sans pour autant ré-écrire à chaque fois l'ensemble du code. Ces parties de programmes peuvent être regroupées dans des fonctions qui faciliteront la lecture et la compréhension du programme principal.
Voici un exemple qui illustre la nécessité et l'intérêt de ce concept.
Supposons que vous deviez écrire un script qui calcule le volume d'un parallélépipède pour différentes valeurs de ses côtés. On pourrait écrire par exemple quelque chose comme :
# cas n°1
longueur = 5
largeur = 10
hauteur = 8
volume = longueur * largeur * hauteur
# cas n°2
longueur = 15
largeur = 12
hauteur = 10
volume = longueur * largeur * hauteur
# cas n°3
longueur = 10
largeur = 10
hauteur = 20
volume = longueur * largeur * hauteur
On constate tout de suite que l'on a écrit à peu près 3 fois la même chose, en ne modifiant à chaque fois que la valeur des variables...
Il serait donc judicieux de coder une seule fois les instructions communes aux différentes parties du script ci-dessus, tout en permettant à ces instructions de "s'adapter" à des valeurs de variables différentes :
fonction permettant de calculer le volume :
volume = longueur x largeur x hauteur
# cas n°1
utiliser la fonction avec les valeurs 5, 10 et 8
# cas n°2
utiliser la fonction avec les valeurs 15, 12 et 10
# cas n°3
utiliser la fonction avec les valeurs 10, 10 et 20
Le script est ainsi beaucoup plus concis et lisible, sa maintenance et son débogage en seront très facilités !!
Une fonction est donc une sorte de "programme dans le programme".
Comme dans tout langage, une fonction en Python suit des règles d'écriture et d'utilisation précises.
La définition d'une fonction correspond à l'écriture des instructions qui effectueront la tache pour laquelle elle est conçue.
Dans le cas d'un langage compilé ( comme C, Java, C++,...), la définition des fonctions peut se faire n'importe où dans le code, en dehors du corps principal du programme.
Dans le cas des langages de script comme Python, la définition des fonctions doit se faire avant leur utilisation dans le code, donc généralement en tout début de script, après les éventuelles instructions
d'importation de module(s).
def nom_de_la_fonction(paramètres):
.....................
Instruction(s)
.....................
return résultat
def
def
.return
suivi du résultat du traitement ( une valeur particulière ou le contenu d'une variable ) permet de retourner ( c'est à dire,
"renvoyer" ) le résultat du travail de la fonction. Attention, le fait qu'une fonction retourne un résultat ne veut pas dire qu'elle l'affiche !...Pour l'exemple d'introduction, on pourrait ainsi définir une fonction calcul_volume()
de la façon suivante :
def calcul_volume(longueur, largeur, hauteur): # la fonction a besoin de 3 paramètres pour faire le calcul du volume
volume = longueur * largeur * hauteur
return volume
Une fonction retourne donc un résultat d'un certain type.
Les questions du type et du ( ou des ) paramètre(s) d'une fonction sont celles qu'il faut TOUJOURS se poser avant de construire une fonction.
float
:
def volume_sphere(r):
volume = (4/3)*pi*r**3
return volume
def message_de_bienvenue( nom ):
print('Bonjour', nom ,'et bienvenue dans ce programme.')
def division( n1, n2 ):
quotient = n1 // n2
reste = n1 % n2
return quotient, reste
L'appel d'une fonction correspond au moment où on l’exécute; cet appel prend la forme d'une instruction généralement placée dans le corps principal du programme. ( mais pas obligatoirement : une fonction peut appeler une autre fonction ! )
Lors de l'appel d'une fonction, il se passe en réalité deux processus au même endroit du script :
( Tout se passe donc comme si l'instruction d'appel avait été remplacée dans le code par les instructions de la fonction. )
L'appel d'une procédure ( fonction sans résultat retourné ) se fait simplement en indiquant son nom, avec entre parenthèses, la liste du ( ou des ) arguments(s) à lui passer, dans le même ordre que celui des paramètres
dans sa définition.( si la procédure n'a aucun paramètre, on ne lui passe aucun argument ! ).
Les arguments peuvent être des valeurs, des noms de variables, des expressions, etc...
nom_de_la_fonction(arg1, arg2,...)
Lors de l'appel d'une fonction par contre, il faut en plus "faire quelque chose" du résultat retourné par la fonction, comme l'afficher ou l'affecter à une variable :
print(nom_de_la_fonction(arg1, arg2,...)) # affichage de la valeur retournée par la fonction
result = nom_de_la_fonction(arg1, arg2,...) # la variable result contiendra la valeur retournée par la fonction
# définition des fonctions et procédures
def message_de_bienvenue( nom ):
print('Bonjour', nom ,'et bienvenue dans ce programme.')
def volume_sphere(r):
volume = (4/3)*pi*r**3
return volume
def division( n1, n2 ):
quotient = n1 // n2
reste = n1 % n2
return quotient, reste
def calcul_volume(longueur, largeur, hauteur): # la fonction a besoin de 3 paramètres pour faire le calcul du volume
volume = longueur * largeur * hauteur
return volume
# Programme principal
pi = 3.1415
nom = input('Quel est votre nom ?')
message_de_bienvenue( nom ) # appel de la procédure d'affichage du message d'accueil
volume = volume_sphere(5) # calcul du volume d'une sphère de rayon r = 5
print( volume )
volume = calcul_volume(10, 5, 2)
print( volume )
quotient, reste = division(125, 23) # il faut passer 2 arguments, et récupérer 2 résultats !!
print('Quotient =', quotient)
print('Reste =', reste )
On peut remarquer qu'il n'y a pas d'ordre particulier pour la définition des fonctions, du moment que cette définition se fait avant l'appel de la fonction.
Dans l'exemple précédent, vous vous êtes ( peut-être ) étonnés de voir le même nom de variable ( volume, nom, quotient,... ) dans le programme principal et dans la définition des fonctions; s'agit-il pour autant de la même variable ? En réalité, c'est un peu plus complexe...
La portée d'une variable indique la zone du code dans laquelle cette variable est utilisable, ou au contraire, à quels endroits du script elle est "inconnue" :
Quand un script rencontre le nom d'une variable dans une fonction, il va rechercher cette variable en élargissant son champ de recherche : il cherche d'abord cette variable dans la portée de la fonction ( et notamment dans ses paramètres ); s'il ne la trouve pas, il passe alors au "niveau supérieur" et la recherche dans le corps principal du script. Si il ne la trouve toujours pas, alors il génère une erreur.
Si on reprend une partie du script du paragraphe précédent :
# définition des fonctions et procédures
def message_de_bienvenue( nom ):
print('Bonjour', nom ,'et bienvenue dans ce programme.')
def volume_sphere(r):
volume = (4/3)*pi*r**3
return volume
def division( n1, n2 ):
quotient = n1 // n2
reste = n1 % n2
return quotient, reste
# Programme principal
pi = 3.1415 # variable globale
nom = input('Quel est votre nom ?')
message_de_bienvenue( nom ) # appel de la procédure d'affichage du message d'accueil
volume = volume_sphere(5) # calcul du volume d'une sphère de rayon r = 5
print( volume )
quotient, reste = division(125, 23) # il faut récupérer 2 résultats !!
print('Quotient =', quotient)
print('Reste =', reste )
volume_sphere()
) tant qu'elle est initialisée avant l'appel de la fonction.division()
, la variable r est uniquement locale à la fonction volume_sphere()
message_de_bienvenue()
division()
Cette notion de portée est fondamentale en informatique, elle existe dans tous les langages. C'est ce qui permet aux ordinateurs de gérer efficacement leur mémoire.
Il faut bien en tenir compte et y faire attention, c'est la source de pas mal d'erreurs parfois délicates à corriger : tenter d’accéder à une variable locale à une fonction alors que l'on n'est pas dans cette fonction engendrera une erreur d'exécution, comme si cette variable n'avait jamais été définie du tout...
Inversement, toujours donner le même nom à des variables locales et globales ( comme c'est le cas dans les exemples précédents ) n'est pas une bonne pratique, même si "ça marche !"; donner des noms différents permet de rendre le code plus lisible et de bien distinguer ce qui est local ou global.
def surface_cercle( r ):
pi = 3.1415926
s = pi*r**2
return s
print(pi)
surface = surface_cercle( 12 )
print(surface)
Traceback (most recent call last):
File "cercle.py", line 7, in
print(pi)
NameError: name 'pi' is not defined
Le script génère une erreur : la tentative d'affichage de la variable pi dans le programme principal se solde par un échec, cette variable n'étant que locale à la fonction.
La solution est bien évidemment de définir la variable pi dans le programme principal, et ainsi de la rendre globale :
def surface_cercle( r ):
s = pi*r**2
return s
pi = 3.1415926
print(pi)
surface = surface_cercle( 12 )
3.1415926
452.3893344
>>>
Mais attention : c'est une très mauvaise pratique de multiplier les variables globales; il faut limiter leur nombre au maximum, sinon de nombreuses confusions sont à prévoir, comme modifier une variable globale alors
qu'on croyait modifier une variable locale ( ça n'aura pas du tout le même effet !! ).
Pensez-y quand vous codez !
Il est important d'adopter une méthode rigoureuse lors de la construction d'une fonction.
On commence d'abord à réfléchir aux spécifications de cette fonction : quels sont les paramètres qu'elle nécessite ( et donc quels seront les arguments qu'il faudra lui passer ) ( les préconditions ), qu'est-ce qu'elle doit retourner, quel est le type de la variable de retour, etc...( les postconditions ).
Il est d'usage de préciser toutes ces informations dans la docstring ( = "documentation string" ) de la fonction : il s'agit de commentaires placés au début de la définition de la fonction et qui constituent sa documentation
Voici un exemple pour une fonction vue dans le cours :
def division( n1, n2 ):
"""
Fonction pour calculer le quotient et le reste de la division de deux nombres.
Pré :
deux nombres n1, n2
Post :
deux entiers dans l'ordre : quotient, reste de la division de n1 par n2
"""
quotient = n1 // n2
reste = n1 % n2
return quotient, reste
On précise ainsi quelles sont les spécifications en entrée et en sortie de la fonction, mais de plus, cette docstring est alors accessible depuis l'interpréteur Python grâce à la fonction help()
( ceci est valable pour toute fonction ! ) :
>>> help(division)
Help on function division in module __main__:
division(n1, n2)
Fonction pour calculer le quotient et le reste de la division de deux nombres.
Pré :
deux nombres n1, n2
Post :
deux entiers dans l'ordre : quotient, reste de la division de n1 par n2
>>>
DORÉNAVANT, DE LA MÈME MANIÈRE QUE VOTRE CODE DOIT ÊTRE COMMENTÉ, VOS FONCTIONS DEVRONT TOUJOURS FOURNIR A L'UTILISATEUR UNE DOCSTRING.
Écrire une fonction cube()
qui retourne le cube de son paramètre.
Définir une fonction somme1()
qui prend en paramètres 3 nombres ( entiers ou pas ) et qui retourne leur somme.
Définir une fonction envers()
qui prend comme paramètre une chaîne de caractères, et qui retourne la chaîne avec ses caractères en sens inverse.
Définir une fonction qui prend un entier en paramètre, et qui affiche la table de multiplication de cet entier ( multiples de 1 à 9 seulement )
Utiliser ensuite cette fonction pour afficher les tables de multiplication de 1 à 10.