Pour simplifier la rédaction et la lisibilité des programmes, on utilise des fonctions.
On peut créer une fonction pour regrouper un bloc d'instructions soit par ce qu'on l'utilise plusieurs fois dans le programme, soit parce que cela permet d'identifier clairement une étape du programme.
Plus généralement, on peut voir les fonctions comme de nouvelles fonctionnalités qu'on rajoute à Python.
Pour définir une fonction, il faut utiliser la syntaxe :
Le nom de la fonction, avec les mêmes règles syntaxiques que les noms de variables.
Les parenthèses qui peuvent être vides ou contenir les noms de paramètres, séparés par des virgules s'il y en a plusieurs.
Les deux points à la fin de la ligne
Sur les lignes suivantes, les instructions ont toutes la même indentation, c'est-à-dire le décalage vers la droite par rapport à la première ligne. C'est ce qui permet à Python de déterminer à quel moment s'arrête la fonction.
Un premier exemple de fonction
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Évaluations restantes : ∞/∞
Pour l'utiliser, il exécuter le programme et ensuite taper bonjour() dans le terminal, en mettant bien les parenthèses vides.
La fonction input
La fonction bonjour utilise la fonction Python input. Cette fonction demande une valeur à l'utilisateur, éventuellement en lui donnant un message d'explication.
Pour mémoriser la valeur entrée par l'utilisateur, il faut l'affecter à une variable : une_variable=input("La question").
L'affichage dans le terminal n'est pas toujours le même selon l'IDE utilisé. Normalement, la question est affichée dans le terminal et la réponse de l'utilisateur s'écrit juste à côté. C'est le comportement que l'on retrouve dans Thonny. Pour plus de lisibilité, c'est aussi le comportement que nous présenterons dans les exemples.
Nous utiliserons rarement cette fonction, puisqu'il y a un moyen bien plus efficace pour obtenir des valeurs pour les fonctions. Elle pourra être utile pour les jeux où il faut demander au joueur ce qu'il veut faire à chaque tour.
Fonctions et variables
On reprend l'exemple précédent :
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Évaluations restantes : ∞/∞
Exécuter le programme et appeler la fonction dans le terminal.
Taper nom dans le terminal et observer le résultat.
Explications
Vous devriez obtenir quelque chose ressemblant à cela :
>>> bonjour()# (1)!Quel est ton nom ? BobBonjour Bob>>> nom# (2)!Traceback (most recent call last):
File "<console>", line 1, in <module>NameError: name 'nom' is not defined
On appelle la fonction.
On demande la valeur de la variable nom.
On obtient un message d'erreur nous disant que la variable nom est inconnue. C'est parce que cette variable est une variable locale de la fonction. Sa valeur n’est pas accessible après l’appel à la fonction. Nous reviendrons sur les variables locales et globales plus tard dans l'année.
Garder une valeur après l'appel d'une fonction
Comme nous venons de le voir, les valeurs calculées dans la fonction sont perdues à la fin de l'appel.
Si on veut garder une valeur, il faut que la fonction la renvoie à la fin de son appel. On utilise pour cela le mot-clef return.
Lors de l'exécution d'une fonction, si une instruction de la forme returnexpression est exécutée, la valeur de expression est renvoyée et peut être affectée à une variable.
Après l'exécution d'une instruction contenant un return, l'exécution de la fonction s'arrête, même s'il reste des instructions. C'est pourquoi on met en général cette instruction à la fin de la fonction.
On appelle la fonction et le terminal affiche la valeur renvoyée. Avec la fonction bonjour qui ne renvoyait rien, il n'y avait pas de valeur affichée à la fin de l'appel.
On appelle la fonction en affectant son résultat à une variable.
On vérifie que la variable a bien la valeur attendue.
Vous pouvez tester la fonction ici
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Évaluations restantes : ∞/∞
Lorsque dans la description d'une fonction dans un exercice on vous demandera de renvoyer une valeur, c'est qu'il faudra utiliser return.
Exercice 6
Modifier la fonction ci-dessous pour qu'elle renvoie le nom entré par l'utilisateur. Il ne faut pas modifier la question posée et le message affiché. Il faut juste rajouter une ligne à la fonction.
Vous pouvez remarquer qu'il y a un nouveau bouton ! . Il vous permet de valider votre code. Après avoir testé votre fonction, vous pouvez appuyer sur ce bouton pour savoir si votre réponse est bonne ou pas. Votre fonction va passer un certain nombre de tests secrets. Si votre code est bon, vous aurez accès au corrigé et éventuellement à des remarques supplémentaires. Sinon vous aurez un message d'erreur.
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
L'indentation (les espaces au début d'une ligne) permet à l'interpréteur de savoir les instructions qui font partie d'une fonction ou non. Il est très important de respecter cette syntaxe. En général, on utilise des indentations de 4 espaces. Mais on peut très bien mettre un seul espace ou huit si on veut. Par contre, il faut garder la même indentation tout au long de la fonction.
Le code de cette fonction est valide, avec 4 espaces par indentation.
Le code de cette fonction est valide, avec 1 espace par indentation. On peut voir qu'il n'est pas si évident de remarquer l'indentation.
Le code n'est pas valide parce que la ligne returnz est indentée avec une ligne de moins que la précédente.
Le code n'est pas valide parce que la ligne returnz est indentée avec une ligne de plus que la précédente.
Vous pouvez tester les fonctions ici
Vous pouvez exécuter le programme pour observer l'erreur produite lorsque la fonction exemple3 est lue.
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Évaluations restantes : ∞/∞
Vous pouvez aussi corriger les erreurs d'indentations et vous assurez que le programme est syntaxiquement correct.
Lorsque vous voyez l'erreur IndentationError, vous devez vérifier l'indentation de la ligne indiquée.
Pour éviter les problèmes, il vaut mieux utiliser la touche tabulation (Tab) pour indenter et Shift+Tab pour désindenter. Si plusieurs lignes sont sélectionnées, elles sont toutes indentées ou désindentées en même temps.
Fonctions avec plusieurs return
Lorsqu'il y a plusieurs return dans le code d'une fonction, son exécution s'arrête dès qu'un return est rencontré. C'est la valeur correspondante qui est renvoyée :
defh():return1print("Vous ne me verrez jamais")return2
>>> h()# (1)!1
L'exécution s'arrête dès que la ligne return1 est exécutée.
Pour tester vous même
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Évaluations restantes : ∞/∞
Pour l'instant, cela n'a pas beaucoup d'importance, mais bientôt, nous verrons l'intérêt de mettre plusieurs return dans une même fonction.
Fonctions et paramètres
Vous avez dû remarquer qu'il est pénible de taper à chaque fois une valeur pour la fonction input afin de tester vos fonctions. Les paramètres des fonctions permettent de passer directement une ou plusieurs valeurs à une fonction au moment de l'appel. En utilisant l'historique du terminal, rappeler une fonction avec une valeur particulière se fait beaucoup plus rapidement.
Si on souhaite juste obtenir l'affichage du message, on peut modifier la fonction bonjour ainsi :
defbonjour(nom):print("Bonjour",nom)
On l'utilise ainsi :
>>> bonjour("Bob")Bonjour Bob
Lors de l'appel, on associe la valeur "Bob" au paramètre nom. On dit que "Bob" est un argument, c'est-à-dire la valeur attribuée à un paramètre lors de l'appel.
On peut aussi mettre plusieurs paramètres en les séparant par des virgules :
>>> bonjour2("Alice","Bob")# (1)!Bonjour Alice et Bob
Lors de l'appel, on donne deux arguments : "Alice" qui est associé à nom1 et "Bob" qui est associé à nom2.
Paramètres par défaut
Il est aussi possible de définir des valeurs par défaut. Pour cela, on affecte directement une valeur au(x) paramètre(s) concerné(s). Ces valeurs ne sont utilisées que si aucun argument n’est donné pour ce paramètre.
Le paramètre nom2 a une valeur par défaut : "les autres".
>>> bonjour2("Alice","Bob")# (1)!Bonjour Alice et Bob>>> bonjour2("Alice")# (2)!Bonjour Alice et les autres
On donne une valeur à nom2, qui est donc utilisée à la place de la valeur par défaut.
On ne donne pas de valeur pour nom2. C'est donc la valeur par défaut qui est utilisée.
Vous pouvez tester les deux fonctions ici
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Évaluations restantes : ∞/∞
Plusieurs valeurs par défaut
On peut donner des valeurs par défaut à plusieurs paramètres, mais il faut que ce soit les derniers donnés. Dès qu'on donne une valeur par défaut à un paramètre, il faut que tous ceux qui le suivent dans la définition aient aussi une valeur par défaut.
Lorsqu'il y a plusieurs valeurs par défaut et qu'on veut changer celle du dernier paramètre sans donner explicitement celles des autres, on peut utiliser la syntaxe suivante :
Les trois premiers paramètres reçoivent respectivement les valeurs 14, 25 et 53. Les paramètres param4 et param5 gardent leur valeur par défaut. Et param6 reçoit la valeur "bof".
On peut aussi passer une expression comme argument. Dans ce cas, Python va calculer 1+5 et ensuite calculer le résultat de f(6).
On peut même utiliser un appel à la fonction comme argument d'un autre appel. Dans ce cas, Python va calculer f(4), qui vaut 7 et ensuite calculer f(7).
Vous pouvez tester la fonction ici
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Évaluations restantes : ∞/∞
Bien entendu, il y a de nombreuses façons d'écrire cette fonction.
Mettre une expression après return
Dans l'exemple précédent, il y avait des étapes de calcul pour pouvoir mettre une variable après return.
Mais on peut tout à fait mettre une expression après return, comme dans l'exemple ci-dessous :
defg(x):return3*x*x-12*x+7
>>> g(1)-2>>> g(f(1))# (1)!43
Bien entendu, on peut utiliser le résultat de l'appel à une fonction dans un appel d'une autre fonction.
Vous pouvez tester la fonction ici
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Évaluations restantes : ∞/∞
Utiliser une fonction dans un autre fenêtre de l'IDE
Tous les IDE d'une même page partagent le même espace mémoire. Cela veut dire que si vous avez mis en mémoire la fonction f de l'exemple précédent dans son IDE, vous pouvez aussi l'utiliser dans celui de g et réciproquement.
print ou return
Même si dans de nombreux cas, on a l'impression que le résultat obtenu dans le terminal est le même, utiliser print ou utiliser return n'est pas du tout équivalent.
Lorsqu'on affiche quelque chose avec print, cet affichage n'est que pour l'utilisateur et il ne peut pas être utilisé dans un calcul.
Lorsqu'on renvoie une valeur avec return, on peut affecter cette valeur à une variable ou l'utiliser dans une expression pour en faire autre chose.
De façon générale, à moins de vouloir afficher plusieurs lignes de texte, nous utiliserons quasi-systématiquement return.
# Tests
(insensible à la casse)(Ctrl+I)