CHAPITRE 4 : LES FONCTIONS
LES LANGAGES DE
PROGRAMMATION :
LE PYTHON
Isoler une instruction
Lors de l'écriture des programmes, ils arrivent fréquemment que certaines instructions reviennent
plusieurs fois. n=1
while n<11:
print(n*2, end=‘ ‘) n=n+1
print("---") print()
n=1
while n<11:
print(n*3, end=‘ ‘) n=n+1
print("---") print()
n=1
while n<11:
print(n*4, end=‘ ‘) n=n+1
print("---") print()
Voici un exemple de programme dans lequel il y a des répétitions.
Ce programme permet d'afficher les dix
premiers éléments des tables de multiplication par 2,3 et 4.
Dans un premier temps, on remarque que l'instruction
print("---") print()
est répétée trois fois.
Au lieu de répéter la totalité de cette instruction, on peut créer une fonction qui contiendra ces instructions, et utiliser cette fonction autant de fois qu'il est nécessaire.
3
Je vais donc définir la fonction que je vais appeler : tireruntrait La syntaxe d’une fonction est la suivante :
def nomdelafonction(liste de paramètres) : bloc d’instructions
Vous pouvez choisir n’importe quel nom pour la fonction que vous créez.
Eviter les caractères accentués.
Vous ne pouvez pas utiliser les mots réservés au langage.
N’oubliez pas les : et l’indentation
Dans le cas qui m'intéresse, je vais donc créer la fonction suivante :
On utilise alors cette fonction dans le programme principal, comme si c'était une instruction de langage
def tireruntrait():
print("---")
print()
def tireruntrait():
print("---") print()
n=1
while n<11:
print(n*2, end=‘ ‘) n=n+1
tireruntrait() n=1
while n<11:
print(n*3, end=‘ ‘) n=n+1
tireruntrait() n=1
while n<11:
print(n*4, end=‘ ‘) n=n+1
tireruntrait()
La ou les définition(s) de fonction se place(nt) avant le programme
principal, si bien que l'organisation générale du programme est celle décrite ci-contre:
L'instruction
print("---") print()
que l'on isole par la définition de la fonction tireruntrait s'appelle le corps de cette fonction.
L'instruction
tireruntrait() s'appelle un appel de la fonction tireruntrait.
Exécuter cette instruction a pour effet d'exécuter le corps de la fonction à l'endroit ou s'effectue l'appel
Exercice 1 : vous souhaitez écrire un programme qui demande deux fois le même mot de passe à son utilisateur.
Le mot de passe que vous choisissez est 4242. Écrivez un programme qui attend ce code une première fois, en le demandant de manière répétée par une ligne contenant « Entrez le code : », puis qui une fois ce code entré, affiche « Encore une fois. » et attend le code à nouveau, avant d'afficher « Bravo. » et de se terminer (vous trouverez sans doute cela plus clair avec l'exemple ci-dessous).
L'objectif de cet exercice est d'utiliser une fonction pour éviter de recopier deux fois les instructions qui permettent d'attendre le code 4242.
Exemple entrée : 4241 4342 4242 2424 4242 sortie :
Entrez le code : Entrez le code : Entrez le code : Encore une fois.
Entrez le code : Entrez le code : Bravo.
Fonction à un paramètre
Nous venons de voir comment les fonctions permettent d'éviter de répéter exactement les mêmes instructions à plusieurs endroits d'un programme.
Il arrive aussi souvent que l'on répète les mêmes instructions, mais avec de légères
différences d'une version à l'autre. Supposons par exemple que nous souhaitions afficher une ligne d'étoiles au début et une ligne de tirets un peu plus loin. Les instructions
utilisées dans les deux cas seront identiques à un caractère près.
On va donc rendre notre fonction paramétrable avec un argument caractere : def tireruntrait(caractere):
print(caractere*40) print()
On place donc le paramètre nommé entre les parenthèses après le nom de la fonction.
Au sein de cette fonction, l'identifiant caractere représente une variable, qui a été initialisée à la valeur indiquée lors de l'appel.
Pour appeler la fonction, on place la valeur entre les parenthèses : tireruntrait("*")
Différentes façons d'appeler les fonctions contenant des paramètres
L' appel d'une fonction pose souvent des problèmes aux élèves de NSI.
Ains la fonction précédente :
peut-être appelée de différentes manière : tireruntrait("*") la valeur du paramètre
directement dans l'appel
dans ce cas la variable caractere sera le caractère
"*" dans la fonction
c="*"
tireruntrait(c) la valeur du paramètre
dans une variable
dans ce cas la variable caractere correspondra au contenu de la variable c qui sera le caractère "*" dans la fonction
def tireruntrait(caractere):
print(caractere*40) print()
def tireruntrait(caractere):
print(caractere*20) caractere ="*"
print(caractere*20) print()
caractere = "-"
tireruntrait(caractere) print(caractere)
Pour finir avec les appels de fonction, un exemple un peu surprenant.
Sortie
---
********************
-
On remarque que l'affectation caractere ="*" n'a fonctionné qu'à l'intérieur de la fonction.
En effet, le print(caractere) à la dernière ligne du programme affiche un"-".
Que faut-il en conclure ?
Il y a en fait ici deux variables parametre, une à l'intérieur de la fonction, on dit qu'elle est locale à la fonction, et l'autre à l'extérieur de la fonction, on dit qu'elle est globale au
programme. L'organisation de la mémoire que nous verrons dans le thème 3 permet de créer ces variables locales et globales.
On a donc bien ici deux variables avec le même nom mais qui ont des valeurs différentes.
Exercice 2 : Cette fois-ci, vous souhaitez montrer aux jeunes recrues un programme qui demande deux codes secrets différents.
Vous choisissez 2121 comme deuxième mot de passe. Écrivez un programme qui attend successivement les codes 4242 puis 2121, en affichant cette fois « Premier code bon. » entre les deux, comme montré dans l'exemple.
Ici, écrivez une et une seule fonction pour demander successivement les deux codes. (vous pouvez reprendre le code de l'exercice 1)
Exemple entrée : 12
42345 4242 123 2121 sortie :
Entrez le code : Entrez le code : Entrez le code : Premier code bon.
Entrez le code : Entrez le code : Bravo.
Fonction à un plusieurs paramètres
Dans l'exemple de la fonction qui affiche plusieurs fois une ligne de
caractères, on peut imaginer que le nombre de fois où le caractère doit être affiché n'est pas toujours identique et doit être passé en paramètre lors de l'appel.
Pour cela, il suffit de séparer les paramètres par une virgule : tireruntrait("*" , 40)
tireruntrait("-" , 20)
Pour pouvoir faire un tel appel, il faut cependant avoir défini dans la déclaration de la fonction que celle-ci prend un deuxième paramètre, cette fois un entier, puis modifier les instructions pour qu'elles utilisent la variable correspondante. Comme pour l'appel, on ajoute simplement un paramètre dans la déclaration en le séparant du premier par une virgule.
On nommera par exemple ce paramètre longueur : def tireruntrait(caractere, longueur):
print(caractere*longueur) print()
Remarque : si l'on a défini que la fonction prenait deux paramètres, on ne peut plus l'appeler en n'en fournissant qu'un seul. En Python, il est toutefois possible de rendre certains paramètres facultatifs.
def tireruntrait(caractere, longueur):
print(caractere*longueur) n=1
while n<11:
print(n*2, end=‘ ‘) n=n+1
tireruntrait() n=1
while n<11:
print(n*3, end=‘ ‘) n=n+1
tireruntrait() n=1
while n<11:
print(n*4, end=‘ ‘) n=n+1
tireruntrait()
Reprenons notre programme initial. Il est formé de trois blocs qui permettent chacun d'afficher la table de 2,3 et 4.
Exercice 3 : écrivez une fonction table qui prend en argument une base sous forme d'un entier afin d'afficher les dix premières valeurs de n'importe quelle table de
multiplication de la base passé en argument.
Exemple : Entrée table(2)
tireruntrait("-",27) table(3)
Sortie
2 4 6 8 10 12 14 16 18 20
---
3 6 9 12 15 18 21 24 27 30
Exercice 4 : Votre programme doit lire le nombre de lignes et de colonnes de la feuille, puis le motif à afficher sous la forme d'un caractère. Il doit alors afficher le motif de sorte qu'il remplisse chaque cellule de la feuille.
Exemple 1 entrée : 4
9 F
sortie : FFFFFFFFF FFFFFFFFF FFFFFFFFF FFFFFFFFF
Exemple 2 entrée : 8
3 P
sortie : PPP PPP PPP PPP PPP PPP PPP PPP
13
Exercice 5 : modifier la fonction table de l'exercice 3 qui en plus de pouvoir choisir la base permet également le choix du début et de la fin des termes à afficher. Vous améliorerez l'affichage du résultat (cf. exemple)
Exemple : Entrée
table(8,13,16) Sortie
13 x 8 = 104 14 x 8 = 112 15 x 8 = 120 16 x 8 = 128
Retourner une valeur
Les fonctions que nous avons écrites effectuaient des opérations, mais n'avaient cependant aucune influence sur la suite de l'exécution du
programme. Supposons par exemple que nous ayons souvent besoin de calculer la valeur absolue d'un nombre, de cette façon :
if nombre < 0:
distance = -nombre else:
distance = nombre
Nous pouvons écrire une fonction qui prend en paramètre un nombre et calcule sa valeur absolue. Il nous faut cependant un moyen pour retransmettre cette valeur au programme.
Au moment de l'appel, l'idée est de considérer dans le programme, qu'une fonction appelée a une valeur que l'on peut utiliser ensuite.
Cette valeur, calculée par les instructions de la fonction, peut alors être affectée à une variable.
On pourrait ainsi écrire notre programme en utilisant la fonction valeurAbsolue : distance1 = valeurAbsolue(nombre1);
distance2 = valeurAbsolue(nombre2);
Notre fonction valeurAbsolue prendrait en paramètre une valeur et retournerait sa valeur absolue. Voyons maintenant comment écrire une telle fonction.
Pour que la fonction puisse effectivement retourner une valeur, il faut qu'elle contienne une instruction, composée du mot-clé return et de la valeur que l'on veut retourner.
L'instruction return quitte la fonction et transmet la valeur qui suit au programme appelant :
def valeurAbsolue(valeur):
if valeur >= 0:
valAbsolue = valeur else:
valAbsolue = -valeur return valAbsolue
RQ. Une telle fonction est ainsi comparable à la notion de fonction mathématique : valeurAbsolue(x) aura pour valeur la valeur absolue du contenu de la variable x.
Il est possible de mettre plusieurs instructions return à l'intérieur d'une fonction.
Chacune d'entre elles doit être suivie d'une valeur du format attendu.
Il est également important que quoi qu'il arrive dans la fonction, elle retourne une valeur, donc exécute une instruction return.
Notre fonction peut ainsi s'écrire plus simplement :
def valeurAbsolue(valeur):
if valeur < 0:
return -valeur return valeur
Exercice 6 : Des jeunes attirent à présent votre attention sur des suites de nombres entiers qui semblent avoir certaines similitudes, surtout sur leurs terminaisons.
Dans cette suite, le nombre qui suit un nombre terme est :
• si terme est pair, terme ÷ 2 ;
• sinon, terme × 3 + 1.
Vos compagnons ont remarqué que, quel que soit le nombre dont on part, en allant d'un terme à l'autre en suivant ces propriétés, on finit toujours par tomber sur le nombre 1. Ainsi, ils souhaitent que leur écriviez une fonction qui, pour un terme, renvoie le terme suivant dans la suite.
Votre programme doit afficher les termes de la suite qui succèdent à celui fourni sur l'entrée, séparés par des espaces, jusqu'à ce que le nombre 1 soit atteint.
Important : vous devez utiliser une fonction qui prend un terme en paramètre, et retourne le suivant.
Exemple entrée : 7
sortie :
22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
La suite de nombre obtenue en appliquant cet algorithme est appelée la suite de Syracuse.
De cette suite est issue la conjecture de Syracuse, qui propose que l'on retombera en effet toujours sur 1, quel que soit le nombre de départ. Cela n'a jamais été prouvé, mais le contraire non plus ! Cette suite a commencé à être largement étudiée dans les années 1960 aux États-Unis, après que le mathématicien allemand Collatz l'a présentée à un collègue de l'université de Syracuse, d'où son nom.
Les mathématiciens ont passé tellement de temps à essayer de démontrer la conjecture que certains parlaient même d'un complot soviétique visant à ralentir la recherche américaine pendant la guerre froide !
17
Récupérer plusieurs valeurs
Une fonction peut avoir plusieurs paramètres et renvoyer plusieurs résultats.
Par exemple, voici une fonction qui calcule et renvoie la somme et le produit de deux nombres donnés en entrée.
def somme_produit(a,b):
"""Calcule la somme et le produit de deux nombres"""
s = a + b p = a * b return s, p
som, pro = somme_produit(6,7)
La dernière ligne appelle la fonction avec les arguments 6 (pour le paramètre a) et 7 (pour le paramètre b).
Cette fonction renvoie deux valeurs, la première est affectée à som (qui vaut donc ici 13) et la seconde à pro (qui vaut donc 42).
Rq. la fonction retourne en fait un tuple de valeur dont chaque valeur est affecté à une variable.
Exemple a, b = 5, 6
Variables globales
Lorsque vous définissez des variables à l'intérieur du corps d'une fonction, ces variables ne sont accessibles qu'à la fonction elle-même.
On dit que ces variables sont des variables locales à la fonction.
Ainsi une variable globale est utilisable par une fonction (en tant qu'argument par exemple) , mais la fonction ne peut pas la modifier, sauf si….
def tireruntrait(caractere):
print(caractere*20) caractere ="*"
print(caractere*20) print()
caractere = "-"
tireruntrait(caractere) print(caractere)
Rappel : Il y a en fait ici deux variables parametre, une à l'intérieur de la fonction, on dit qu'elle est locale à la fonction, et l'autre à l'extérieur de la fonction, on dit qu'elle est globale au programme.
On a donc bien ici deux variables avec le même nom mais qui ont des valeurs différentes.
Sortie
---
********************
-
19
Si vous avez besoin de définir une fonction qui soit capable de modifier une variable globale, vous devez utiliser l'instruction global. Cette instruction permet, à l'intérieur d'une fonction, d'indiquer quelles sont les variables à traiter globalement.
Modifions le programme précédent ainsi : def tireruntrait():
global caractere print(caractere*20) caractere ="*"
print(caractere*20) print()
caractere = "-"
tireruntrait() print(caractere)
Sortie
---
********************
*
Dans la fonction l'instruction global caractere indique que la variable caractere est une variable globale et non plus locale
L'utilisation de la fonction a cette fois modifiée la valeur de la variable globale caractere.
Le dernier print(caractere) affiche donc la valeur de caractere modifiée par l'appel à la fonction tireruntrait
Attention, il est préférable d'éviter l'utilisation abusive de l'instruction global, c'est une source fréquente d'erreurs surtout dans les gros programme.
Conclusion
Les fonctions sont un outil incontournable pour produire des programmes qui peuvent être repris et étendus. Elles permettent d'une part d'éviter les répétitions de blocs d'instructions similaires, et d'autre part de décomposer le programme en éléments simples.
Pour résoudre un problème très complexe, un moyen efficace consiste à le décomposer en sous-problèmes avant de résoudre chacun des sous-problèmes indépendamment.
Chaque sous-problème est alors plus simple à appréhender que le problème complet.
On peut ensuite décomposer à leur tour les sous-problèmes obtenus, jusqu'à obtenir des problèmes simples à résoudre. Décomposer un problème en sous-problèmes n'est pas toujours une tâche facile, mais en le faisant, on réduit considérablement la difficulté de sa résolution.
Pour obtenir un source facile à lire et à comprendre, je vous conseille donc d'appliquer les principes suivants à vos programmes :
1. consacrer une fonction à chaque action distincte ;
2. choisir des noms de fonctions qui décrivent ce qu'elles font ;
3. regrouper les parties de code similaires en fonctions, pour éviter les répétitions ; 4. ne pas écrire de fonctions trop longues, éviter de dépasser 25 lignes.
21
Structure d'un programme Python
# Importation de fonctions externes frommath importsqrt
# Définition locale de fonction def occurrence(car,ch):
# Fonction qui permet de compter le nombre
# de caractères (car) dans la chaîne (ch) nc=0
i=0
while i<len(ch):
if ch[i]==car:
nc=nc+1 i=i+1
return nc
# corps principal du programme
phr=input("Veuillez entrer une phrase : ") cch=input("Entrez le caractère à compter : ") no = occurrence(cch,phr)
print("La phrase contient ",no, " caractère", cch) nbr=input("Veuillez entrer un nombre : ")
nbr=float(nbr) rc = sqrt(nbr**3)
print("La racine carrée du cube de ",nbr, " vaut", rc)
Un programme Python contient généralement les blocs suivants dans l'ordre :
Structures d'initialisation
(importation de fonctions (en nombre quelconque ) et/ou de classes,
définition de variables globales
Le corps principal du programme qui fait appel aux fonctions
définies précédemment en
transmettant une série d'arguments Définitions locales de fonctions avec une liste de paramètres
(variables locales) sauf si elles sont spécifiées comme étant globales
Casse-tête 1 Casse-tête 2 def olala(x) :
global z z=z-x return x*x z=10
a=olala(z)
print(‘a:’,a, ‘ z:’,z) Qu’affiche le script ? A. a : 0 z : 0
B. a : 100 z : 0 C. a : 100 z : 10
def olala(x) : global z z=z-x return x*x z=10
a=olala(10)*olala(z) print(‘a:’,a, ‘ z:’,z) Qu’affiche le script ? A. a : 0 z : 0
B. a : 100 z : 0 C. a : 100 z : 10