Les fonctions
Ce que ce chapitre apporte 6 points
- Utiliser une fonction intégrée comme une boîte noire : des arguments en entrée, une valeur rendue en sortie.
- Remplacer Random par une saisie pour qu'un programme redevienne vérifiable.
- Écrire une fonction avec ses paramètres et sa variable de retour, sans forme Return.
- Dérouler un appel : évaluation des arguments, réception par les paramètres, retour de la valeur.
- Distinguer l'appel dans une expression de la forme Call, et dire laquelle convient.
- Expliquer pourquoi une variable du programme principal n'existe pas dans une fonction, et pourquoi un tableau passé en paramètre, lui, est partagé.
Une fonction de Flowgorithm se crée par le menu Program, puis Add Function, et prend place dans son propre diagramme. Le programme principal l'appelle de deux façons : au milieu d'une expression quand elle rend une valeur, par une forme Call quand elle ne rend rien. Le chapitre précédent s'est terminé sur un défaut : la formule du taux de remplissage y était écrite deux fois, à deux lignes d'écart. Rien ne cassait, mais une correction faite d'un côté et oubliée de l'autre aurait donné deux résultats incohérents. Une fonction règle ce défaut : elle nomme une étape, la range dans son propre diagramme, et la rend appelable autant de fois que nécessaire. Ce chapitre distingue les fonctions livrées avec le logiciel de celles que le lecteur écrit, et détaille ce qui entre, ce qui sort, et ce que chaque diagramme voit du reste du programme.
Les fonctions intégrées, des boîtes noires
Size, Len, Char et ToFixed sont des fonctions intégrées. Pour s'en servir, inutile de savoir comment elles calculent : il suffit de savoir ce qu'elles reçoivent, les arguments entre parenthèses, et ce qu'elles rendent. La valeur rendue prend la place de l'appel dans l'expression.
| Fonction | Reçoit | Rend |
|---|---|---|
ToFixed(r, i) | un réel et un nombre de décimales | le réel écrit en texte avec i décimales |
Len(s), Char(s, i) | un texte (et un indice) | sa longueur, ou le caractère d'indice i |
Size(t) | un tableau | son nombre de cases |
Random(n) | un entier | un entier au hasard, de 0 à n - 1 |
Random sert à simuler une mesure. Random(101) rend un entier de 0 à 100, comme un niveau en pourcentage :
Un capteur simulé. Chaque exécution tire une nouvelle valeur.
Exécuter ce programme plusieurs fois : la valeur change à chaque exécution. C'est précisément ce qui le rend impossible à tester. Pour vérifier le cas 90, qui doit afficher « Niveau acceptable », il faudrait attendre que le hasard le tire, et un résultat que l'on ne peut pas reproduire ne se vérifie pas. La version de test remplace donc l'affectation par une forme Input, Input niveau : la valeur est alors choisie, et chaque cas se rejoue à volonté. Random ne revient qu'une fois le programme vérifié.
La version de test. Exécuter avec 90, la frontière : « Niveau acceptable ». Exécuter à nouveau en saisissant 91 : « Débordement imminent ».
1.Pourquoi remplacer niveau = Random(101) par une saisie avant de tester ?
2.Quelles valeurs Random(10) peut-il rendre ?
Écrire ses propres fonctions
Size, Len et ToFixed arrivent avec l'interpréteur. Les étapes propres à un programme, elles, n'existent nulle part : elles se rédigent. Flowgorithm permet d'ajouter ses propres fonctions dans le même fichier, chacune dans son diagramme, et le programme principal les appelle ensuite comme les autres.
Une fonction définie par l'utilisateur répond à trois besoins. Nommer une étape : CalculerTaux(volume, capacite) se lit mieux qu'une formule au milieu du programme. Réutiliser : la formule écrite une fois sert à chaque appel, et une correction s'applique partout. Tester à part : la fonction se vérifie seule, sur des valeurs choisies, avant d'être branchée dans le programme.
Chaque fonction a son propre diagramme. Il commence par une pilule portant son en-tête, le nom de la fonction suivi de ses paramètres, comme CalculerEnergie(puissanceKw, dureeH) sur la figure ci-dessous, et finit par sa propre pilule de fin. Un paramètre est une variable de la fonction, déclarée avec un type dans cet en-tête, et non par une forme Declare ; le logiciel écrit ce type dans la pilule, devant le nom du paramètre. Un argument est la valeur transmise au moment de l'appel : le paramètre reçoit l'argument.
Une fonction qui retourne une valeur a un type de retour et une variable de retour, déclarée dans la fonction : la fonction rend le contenu de cette variable quand elle se termine. Sa pilule de fin affiche alors Return resultat : ce n'est pas une forme que l'on ajoute, c'est l'en-tête qui l'écrit. Il n'existe pas de forme « Return » à placer dans le diagramme.
Une fonction qui ne rend rien s'appelle par une forme Call, un rectangle bordé de deux traits verticaux qui porte le nom de la fonction et ses arguments : l'exécution entre dans la fonction, puis reprend à la forme suivante, sans rien ranger.
La valeur rendue remplace l'appel.
energie = CalculerEnergie(7.5, 6) se lit en deux temps : la fonction s'exécute, puis sa valeur prend la place de l'appel dans l'expression, comme si elle y avait été écrite.
C'est pourquoi une fonction qui ne range rien dans sa variable de retour arrête le programme : il n'y a rien à mettre à la place de l'appel. Et c'est pourquoi une fonction qui ne rend rien s'appelle par une forme Call, jamais au milieu d'un calcul.
Cette définition écarte deux idées reçues. Une fonction n'est pas un raccourci d'écriture recopié à l'endroit de l'appel : c'est un diagramme distinct, où l'exécution entre, puis d'où elle ressort. Et la valeur rendue ne se range nulle part d'elle-même : le programme qui appelle doit la récupérer, sans quoi elle est perdue.
Le programme principal et deux fonctions, chacune dans son diagramme. CalculerEnergie retourne une valeur ; AfficherBilan affiche et ne retourne rien. Exécuter avec 7,5 kW pendant 6 heures, puis suivre en pas à pas : l'entrée dans la fonction et le retour de la valeur se voient forme par forme.
Le déroulement d'un appel
Dérouler en pas à pas avec une puissance de 7,5 kW pendant 6 h. À l'affectation, l'exécution entre dans CalculerEnergie : la fenêtre des variables porte alors le nom de la fonction en tête, et ne montre plus que puissanceKw, dureeH et resultat. Les variables du programme principal n'y figurent plus, parce que la fonction ne les voit pas. Puis l'exécution revient au programme principal, où energie reçoit la valeur rendue. L'appel suivant, par la forme Call, entre dans AfficherBilan, qui affiche Presse 2 : 45.0 kWh. L'argument puissance est reçu par le paramètre puissanceKw, et l'argument duree par le paramètre dureeH : les noms n'ont pas à correspondre, et un argument peut aussi être une valeur écrite directement, comme "Presse 2".
Un appel se déroule toujours dans le même ordre, et le pas à pas le montre forme par forme.
- Les arguments sont évalués dans le programme principal :
puissancevaut 7.5,dureevaut 6. - L'exécution entre dans le diagramme de la fonction, et les paramètres reçoivent ces valeurs, dans l'ordre de l'en-tête :
puissanceKwprend 7.5,dureeHprend 6. Le programme principal attend. - La fonction exécute ses propres formes, avec ses propres variables.
- À sa pilule de fin, l'exécution revient au point d'appel, et le contenu de la variable de retour remplace l'appel dans l'expression : l'affectation devient
energie = 45.
La transmission se fait donc par position, et non par nom : le premier argument va au premier paramètre, le deuxième au deuxième. Leur nombre doit correspondre à celui des paramètres, sinon l'appel est refusé. Un argument n'est pas forcément une variable : une expression convient aussi, comme CalculerTaux(volumes[heurePic], capacite) plus loin dans ce chapitre, car c'est sa valeur qui part dans la fonction. Une fonction peut enfin en appeler une autre, au troisième temps : le programme principal attend alors la première fonction, qui attend elle-même la seconde, et les valeurs remontent dans l'ordre inverse.
| La fonction… | Elle s'appelle… | Exemple |
|---|---|---|
| retourne une valeur | dans une expression : affectation, sortie | energie = CalculerEnergie(puissance, duree) |
| ne retourne rien | par la forme Call | AfficherBilan("Presse 2", energie) |
La variable de retour se remplit comme n'importe quelle variable, par une affectation ordinaire. Rien ne la distingue au moment où elle est écrite : elle est spéciale par son nom, celui que l'en-tête désigne et que la pilule de fin affiche. C'est sa valeur au moment où la fonction se termine qui est rendue.
La fonction CalculerTaux retourne une valeur. Comment récupérer cette valeur dans le programme principal ?
Le calcul est juste, mais rangé dans la mauvaise variable. Exécuter : le message nomme la fonction et la variable restée vide.
Exécuter cette version : le produit est bien calculé, mais dans produit, alors que la pilule de fin annonce Return resultat. La page s'arrête sur CalculerEnergie se termine sans avoir rangé de valeur dans resultat. Aucune forme Return n'aurait signalé l'oubli, puisqu'il n'en existe pas : le seul lien entre le calcul et la valeur rendue est le nom de la variable. Avant de lancer une fonction, vérifier que ce nom reçoit bien une valeur.
Chacun ses variables
Une valeur simple est ainsi fermée des deux côtés : elle n'entre dans une fonction que par un paramètre, et n'en sort que par la valeur rendue. La version suivante l'oublie.
Une version fautive : la fonction ne reçoit que la puissance, et calcule avec la durée du programme principal. Exécuter pour voir l'erreur : la fonction ne connaît pas duree, qui appartient au programme principal.
Chacun ses variables : celles d'une fonction ne se voient pas depuis le programme principal, et inversement. Exécuter cette version : l'exécution entre dans CalculerEnergie et s'arrête sur l'affectation, car duree n'y est pas déclarée. Elle n'existe que dans le programme principal. Tout ce dont une fonction a besoin doit lui arriver par un paramètre. Deux variables de même nom, l'une dans la fonction et l'autre dans le programme principal, restent d'ailleurs deux variables distinctes : le nom ne les relie pas.
Cette séparation n'est pas une contrainte gratuite. Une fonction qui lirait duree dans le programme principal ne marcherait que dans un programme qui possède une variable de ce nom : impossible de la tester seule, impossible de la reprendre ailleurs, et son en-tête mentirait sur ce dont elle a besoin. En exigeant que tout passe par les paramètres, Flowgorithm garantit que l'en-tête dit toute la vérité sur ce que la fonction utilise. Python, lui, laisse une fonction lire une variable du programme principal : c'est permis, et c'est justement ce qu'il faut éviter.
Un tableau en paramètre
Un paramètre peut être un tableau. Dans l'en-tête, des crochets vides le signalent, valeurs[] : la fonction reçoit un tableau entier, dont elle ne fixe pas la taille. La fonction ci-dessous compte les relevés qui dépassent un seuil ; elle lit les cases du tableau reçu sans les modifier, et sert deux fois avec deux seuils différents.
Un paramètre tableau. Dans la fonction, Size(valeurs) rend la taille du tableau transmis. Le second appel, avec le seuil 60, emploie la même fonction sans qu'une ligne de son diagramme change ; avec un seuil de 40, elle rendrait 5 (42, 55, 61, 47 et 58).
Le programme affiche Relevés au-dessus de 50 : 3 puis Au-dessus de 60 : 1. Le second appel figure directement dans la sortie : la valeur rendue s'insère dans le texte, sans passer par une variable. Sur cette page, un appel placé au milieu d'une sortie s'exécute d'un bloc : le pas à pas n'entre que dans un appel qui occupe à lui seul une affectation ou une sortie, ou dans une forme Call.
Un tableau ne se comporte pas comme une valeur simple. Le paramètre valeurs ne reçoit pas une copie de niveaux : il désigne les mêmes cases. Une fonction qui écrit dans une case du tableau reçu modifie donc le tableau du programme principal. CompterDepassements se contente de lire ses cases, et c'est ce que doit faire toute fonction qui ne doit rien changer au tableau. La procédure suivante, elle, écrit dedans.
Un capteur saturé renvoie des niveaux au-dessus de 100 %. Ecreter ne rend rien, et pourtant le tableau du programme principal a changé : les deux noms désignent les mêmes cases. Exécuter en pas à pas, et regarder niveaux au retour de l'appel.
Le programme affiche Deuxième relevé avant l'appel : 108, puis Deuxième relevé après l'appel : 100. Ecreter ne rend aucune valeur, et la forme Call ne range rien : c'est dans les cases mêmes de niveaux que la procédure a écrit.
Un tableau passé en paramètre est partagé. Le pseudo-code du parcours d'algorithmique copiait le tableau à l'appel : la fonction travaillait sur une copie, et le tableau de l'appelant ne bougeait pas.
Flowgorithm ne copie pas : le paramètre désigne les cases du programme principal, et ce que la fonction y écrit y reste. Python fera de même avec une liste. Une valeur simple, elle, arrive toujours comme une copie.
Une fonction se vérifie enfin seule, dans un petit programme qui lit ses arguments et affiche ce qu'elle rend : les cas limites s'y essaient un par un, sans dérouler tout le programme autour.
En Python, une fonction se définit avec def, et l'instruction return rend la valeur, là où Flowgorithm rend le contenu de la variable de retour. Une liste passée en paramètre y est partagée, comme un tableau ici.
1.Dans l'appel ConvertirDebit(pompeEntree), avec l'en-tête ConvertirDebit(litresMinute), qu'est-ce que pompeEntree ?
2.Une fonction reçoit le tableau niveaux dans son paramètre valeurs, et range 100 dans valeurs[1]. Que vaut ensuite niveaux[1] dans le programme principal ?
Fil rouge : la cuve de traitement
Étape 6. Le programme de l'étape précédente est repris tel quel, à une chose près : la formule du taux, qui y figurait deux fois, est isolée dans la fonction CalculerTaux. Le reste ne bouge pas, et le résultat non plus. C'est le propre d'une mise en fonction réussie : elle change la structure du programme, jamais ce qu'il affiche.
Étape 6 du fil rouge. La même cuve qu'au chapitre précédent, mais le calcul du taux n'est plus écrit qu'une fois. Comparer les deux organigrammes : seules deux formes du programme principal changent, le diagramme de CalculerTaux s'ajoute à côté, et les deux sorties sont identiques.
Avec les 24 relevés proposés, le programme affiche Volume moyen : 20187.5 L, soit 71.4 % puis Pic : 26100 L à 12 h, soit 92.3 %. À 12 h, le taux dépasse le seuil haut de 90 %. En pas à pas, observer les cases volumes[0] à volumes[23] se remplir, puis heurePic changer 7 fois pendant la seconde boucle, chaque fois qu'un relevé dépasse le pic retenu. L'exécution entre ensuite deux fois dans CalculerTaux : son paramètre capacite porte le même nom que la variable du programme principal, mais c'en est une autre, qui reçoit sa valeur à l'appel.
1.Une fonction utilise une variable déclarée dans le programme principal. Que se passe-t-il ?
2.L'en-tête d'une fonction désigne resultat comme variable de retour, mais le calcul est rangé dans une variable nommée produit. Que se passe-t-il ?
3.Une fonction qui affiche un bilan et ne retourne rien : comment l'appeler ?
Mettre en pratique
Une station affiche le débit de ses deux pompes en m³/h, alors que les capteurs mesurent en L/min. Écrire la conversion dans une fonction appelée deux fois, et donner l'affichage pour 250 L/min en entrée et 180 L/min en sortie.
La conversion multiplie par 60 (minutes par heure) et divise par 1000 (litres par m³). Écrite une seule fois dans ConvertirDebit, elle est appelée pour chaque pompe :
Une fonction de conversion, deux appels. Le paramètre litresMinute reçoit 250 au premier appel, 180 au second. Exécuter avec 250 et 180, puis saisir 60 comme premier débit : une pompe à 60 L/min donne 3,6 m3/h.
Le programme affiche Pompe d'entrée : 15.0 m3/h puis Pompe de sortie : 10.8 m3/h. Recopier la formule dans les deux affectations aurait donné le même résultat aujourd'hui. Mais une erreur de facteur corrigée dans une copie et oubliée dans l'autre produit deux débits incohérents. Avec la fonction, la formule n'existe qu'à un endroit.
Un programme qui appelle CalculerTaux, puis affiche le taux.
Pour un volume de 21500 L et une capacité de 28274 L, ce programme affiche un taux nul, alors que la fonction est juste. Où est l'erreur ?
La fonction calcule bien resultat et le rend. Mais la forme Call sert aux fonctions qui ne retournent rien : ici, la valeur rendue n'est rangée nulle part. La variable taux du programme principal garde la valeur 0 qu'elle avait reçue avant l'appel, et le programme affiche Taux : 0.0 %.
La correction remplace la forme Call par une affectation : la valeur rendue est rangée dans taux, et l'initialisation devient inutile.
La version corrigée. Exécuter avec les mêmes saisies : le taux passe de 0.0, la valeur perdue du programme précédent, à 76.0 %.
Le programme affiche Taux : 76.0 %. Sans l'initialisation taux = 0, l'erreur serait plus visible : l'exécution s'arrêterait sur la sortie, qui lirait une variable n'ayant jamais reçu de valeur. Donner à resultat le nom taux n'y changerait rien : la variable de retour appartient à la fonction, et le programme principal ne la voit pas. Une valeur rendue se récupère seulement en plaçant l'appel dans une expression.
Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?
Dans la bibliothèque d'exercices
Paramètres et arguments, variable de retour, portée des variables, appel dans une expression.
- Dérouler un appelNiveau 1
- Chacun ses variablesNiveau 1
- Une valeur rendue perdueNiveau 2
- Suivre un appel de fonctionNiveau 2
- Compter les appelsNiveau 3