fonctions python

Identification

Infoforall

6 - Fonctions et variables


Nous allons voir un aspect fondamental de la programmation : la possibilité d'insérer des mini-programmes dans les programmes de façon à créer de nouvelles actions. Vous avez déjà utilisé de nombreuses fois les fonctions. Lesquelles ? print est une fonction, input est une fonction, int est une fonction ...

Il s'agit juste d'un premier contact. Les fonctions vont être vues sur plusieurs activités.

Nous allons voir aujourd'hui comment créer vos propres fonctions si l'action que vous voulez effectuer n'est pas gérée par l'une des innombrables fonctions ou méthodes de Python. Nous allons ici surtout voir comment fonctions et variables interagissent.

Commençons par vous montrer ce qu'on peut faire assez facilement avec les fonctions (et qui peut s'avérer impossible ou presque sans leur intervention ):

animation d'introduction

Téléchargez le code à l'aide de l'image et lancez le. Nous obtenons une animation.

Le mini-projet lié à cette activité vous permettra de vous appropier ce petit programme et vous parviendrez même à le modifier.

Autre chose réalisable : un système réactif. Ici, on reprend l'idée du Simon pour obtenir un système qui réagit aux clics de souris :

Sans fonction, difficile de réaliser ceci...

Logiciel nécessaire pour l'activité : Python 3

Evaluation ✎ : question 07-13-14

Résumé : Version HTML ou fond blanc ou ou PDF (couleur ou gris)

1 - Premieres déclarations de fonctions

Voici un programme contenant deux fonctions nommées fois2 et plus2.

1 2 3 4 5 6 7
def fois2(x): resultat = x * 2 return resultat def plus2(x): resultat = x + 2 return resultat

C'est l'indentation vers la droite qui permet à Python de comprendre quelles instructions appartiennent à la fonction. Il faut donc placer une tabulation ou 4 espaces de suite pour savoir qu’elles sont les instructions rattachées au bloc. De plus, on remarquera qu’on met un double point [ : ] après la première ligne de la déclaration. Sans ce symbole, vous déclenchez une erreur..

01° En regardant le code, que pensez-vous qu'il va se passer lorsqu'on va l'activer ? Les deux fonctions vont-elles réaliser quelque chose ? Une fois que vous pensez avoir la réponse, vérifier en copiant / collant ce script dans Thonny. Lancer. Constatation ?

...CORRECTION...

Il ne va rien se passer.

Par contre, on comprend que l'une doit faire une addition et l'autre une multiplication.

On obtient simplement cela :

résultat dans thonny

Le programme n'a rien fait SAUF déclarer deux nouvelles variables de type function. Vous l'aurez deviné, nous venons de créer deux nouvelles fonctions.

Déclaration de fonction

def fois2(x):

On remarquera immédiatement que :

  1. On commence la déclaration par le mot-clé réservé def suivi du nom de la fonction.
  2. On a nécessairement des parenthèses.
  3. entre les parenthèses, on fournit le nom des variables (ici  x ) qui vont servir à mémoriser les informations reçues. Ces variables particulières se nomment les paramètres de la fonction.
  4. On finit la ligne par un double point  : , nécessaire également.
  5. Les instructions à réaliser sont indentées (4 espaces ou touche TAB)
  6. On finit par return suivi de la réponse qu'on veut renvoyer, ici resultat

02° Dans la Console de Thonny, exécuter les commandes suivantes et observer les réponses. Répondre alors à la question suivante : pour lancer l'exécution d'une fonction doit-on juste taper son nom ou doit-on rajouter les parenthèses ?

>>> plus2 >>> plus2(8) >>> fois2 >>> fois2(20)

...CORRECTION...

On obtient ceci

>>> plus2 <function plus2 at 0x7fd63eabb6a8> >>> plus2(8) 10 >>> fois2 <function fois2 at 0x7fd63eabb730> >>> fois2(20) 40 >>>

On voit donc qu'il faut rajouter les parenthèses.

Si on tape juste le nom, l'interpréteur Python nous dit qu'il trouve bien une fonction qui a ce nom et donne même une indication liée à son identifiant-mémoire.

Qu'est-ce qu'une fonction ? :

On remarque que lorsqu'on tape juste le nom d'une fonction sans placer les parenthèses, l'interpréteur Python renvoie un identifiant mémoire : celui où sont stockées les lignes de code. Une fonction est donc bien une sorte de variable. Elle ne contient pas une valeur mais du code.

Pour les exécuter, il suffit de mettre le nom de la fonction et des parenthèses.

03° Peut-on exécuter autant de fois qu'on le veut le code d'une fonction ? Tenter de le vérifier en faisant l'appel d'une des fonctions plusieurs fois de suite.

Nous avons donc un script qui ne fait RIEN sauf déclarer des fonctions. Fonctions qu'on peut ensuite activées à l'aide de la Console. On peut bien entendu également utiliser les fonctions dans le script lui-même. Dans ce cas, on respecte toujours un ordre de présentation :

  1. D'abord la déclaration des fonctions
  2. Ensuite, le code qu'on pourrait nommer programme principal.

04° Que va contenir le paramètre x de la ligne 1 lorsqu'on lance l'appel suivant :

>>> fois2(12)

...CORRECTION...

Il faut comparer l'appel et la déclaration.

>>> fois2(12)
1
def fois2(x):

On voit que le paramètre x est affecté à 12.

Le code de la fonction permet de voir qu'on va renvoyer 24.

1 2 3
def fois2(x): resultat = x * 2 return resultat

05° Que va contenir le paramètre x de la ligne 5 lorsqu'on lance l'appel suivant :

>>> plus2(80)

...CORRECTION...

Il faut comparer l'appel et la déclaration.

>>> plus2(80)
5
def plus2(x):

On voit que le paramètre x est affecté à 80.

Le code de la fonction permet de voir qu'on va renvoyer 82.

5 6 7
def plus2(x): resultat = x + 2 return resultat

06° Lorsqu'on tape l'instruction suivante dans la console, pourquoi ne pourra-t-on pas utiliser ce résultat pour continuer un calcul ?

Que faudrait-il faire pour garder le résultat en mémoire ?

>>> fois2(15)

...CORRECTION...

On demande à la console d'évaluer fois2(15)

En mode interactif, la console affiche le résultat, c'est son comportement par défaut.

Par contre, on ne mémorise pas le résultat.

Pour cela, il faudrait taper ceci :

>>> m = fois2(15)

✎ 07° Donner le résultat que va renvoyer la fonction suivante. On vous donne le code de la fonction et son utilisation dans la console interactive.

1 2
def facile(x): return x*10 + 5
>>> facile(3)

08° Donner le résultat que va renvoyer la fonction suivante. On vous donne le code de la fonction et son utilisation dans la console interactive.

1 2
def difficile(x, y): return x*10 + y
>>> difficile(5, 6)

...CORRECTION...

Il faut comparer l'appel et la déclaration.

>>> difficile(5, 6)
5
def difficile(x, y):

On voit que le paramètre x est affecté à 5 et que le paramètre y est affecté à 6.

Le code de la fonction permet de voir qu'on va renvoyer 5*10+6, soit 56.

09° Pour valider cette première partie, trouvez les résultats que vont renvoyer les fonctions et les résultats stockés dans les variables a et b après exécution du code ci-dessous.

Vérifiez ensuite en lançant le code réellement.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# 1 - - Déclaration des fonctions - - - - def fois2(x): resultat = x * 2 return resultat def plus2(x): resultat = x + 2 return resultat # 2 - - Programme principal - - - - - nombre = 3 nombre2 = 5 a = plus2(nombre) b = fois2(a) b = b + 1

CLIQUEZ ICI POUR VOIR L'ORDRE DES INSTRUCTIONS EXECUTEES :

Pour visualiser les valeurs des deux variables, deux possibiltés :

  • Soit vous utilisez votre éditeur de code (par exemple VIEW-VARIABLES dans Thonny)
  • Soit vous demandez les résultats via la console interactive :
  • >>> a >>> b

...CORRECTION...

On obtient ceci

  • Mise en mémoire de la fonction fois2
  • Mise en mémoire de la fonction plus2
  • Affectation de 3 dans nombre
  • Affectation de 5 dans nombre2
  • plus2(nombre) renvoie 5.
  • Affectation de 5 dans a
  • fois2(a) renvoie 10 car a est évaluée à 5.
  • Affectation du 10 dans b
  • Evaluation de b + 1 à la valeur 11
  • Affectation du 11 dans b

On retrouve ainsi toutes les choses vues jusqu'à présent.

  • Le code s'exécute séquentiellement
  • On commence par déclarer et mettre en mémoire la fonction fois2 (cela ne l'active pas)
  • Ensuite, on déclare la fonction plus2 (cela ne l'active pas)
  • On lance un appel à plus2 en transmettant 3, et on stocke dans a le résulat, soit 5.
  • On lance un appel à fois2 en transmettant a (donc 5) et on stocke le résultat (10) dans la variable b.

2 - Documentation

Nous avons vu qu'en Python, on peut rajouter des commentaires dans le code en utilisant #.

Nous allons maintenant voir qu'on peut (doit) documenter les fonctions de façon à expliquer ce qu'elles font. Aujourd'hui, nous allons simplement voir comment les documenter et comment lire cette documentation. Les activités suivantes les utiliseront de plus en plus.

Commençons par voir comment insérer de la documentation dans les fonctions : c'est simple, il suffit d'insérer la documentation entre ''' et ''' :

Documentation des fonctions

Les documentations des fonctions peuvent être écrites comme on le veut. Il suffit que le lecteur puisse comprendre vos informations.

Il existe néanmoins des normes de descriptions de façon à ce que des documentations automatisées puissent correctement afficher le contenu de votre documentation en HTML ou PDF. Nous utiliserons ici la norme RST permettant de réaliser une documentation compatible avec Sphinx.

  • :param XXX: pour le contenu attendu dans le paramètre nommé ici XXX pour l'exemple
  • :type XXX: pour préciser le type attendu de cette variable
  • :return: pour expliquer ce que va renvoyer la fonction
  • :rtype: pour préciser le type de la réponse renvoyée

10° Modifier la fonction calculer_moyenne pour qu'elle renvoie la réponse attendue précisée dans les commentaires.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
def calculer_moyenne(note1, note2): '''Renvoie la moyenne des deux notes :param note1: une note dans [0;20] :type note1: int :param note2: une note dans [0;20] :type note2: int :return: la moyenne de note1 et note2 :rtype: float ''' moyenne = 0 return moyenne moy = calculer_moyenne(10, 20)

Exemple d'utilisation dans la console interactive (après avoir mis la fonction en mémoire !)

>>> calculer_moyenne(10, 20) 15.0 >>> calculer_moyenne(10, 14) 12.0

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
def calculer_moyenne(note1, note2): '''Renvoie la moyenne des deux notes :param note1: une note dans [0;20] :type note1: int :param note2: une note dans [0;20] :type note2: int :return: la moyenne de note1 et note2 :rtype: float ''' moyenne = (note1 + note2) / 2 return moyenne moy = calculer_moyenne(10, 20)

La correction est donnée avec un type de documentation respectant RST. Ce n'est pas obligatoire. Vous pouvez voir que cela ne modifie en rien la validité du code Python. La norme de documentation n'est indispensable que si vous voulez utiliser une documentation automatisée.

Il est en réalité inutile de stocker le résultat avant de le renvoyer.

Un code plus concis serait donc 

1 2 3 4 5 6 7 8 9 10 11
def calculer_moyenne(note1, note2): '''Renvoie la moyenne des deux notes :: param note1(int) :: une note dans [0;20] :: param note2(int) :: une note dans [0;20] :: return (float) :: la moyenne de note1 et note2 ''' return (note1 + note2) / 2 moy = calculer_moyenne(10, 20)

11° Utiliser ce nouveau code dans Thonny pour vérifier qu'il fonctionne aussi bien que le précédent.

Nous avons donc vu comment créer la documentation et comment la lire.

Ces deux capacités seront de plus en plus utilisées dans les activités suivantes.

Comprenez bien qu'une documentation de fonction n'est pas simplement un commentaire. Il s'agit réellement d'un outil permettant d'informer les autres utilisateurs de la façon dont il faut utiliser votre fonction. Il s'agit en gros du mode d'emploi de votre fonction. Ces informations doivent être suffisantes pour l'utiliser sans provoquer d'erreurs.

3 - Python interactif

Le code précédent permet donc de créer la fonction et de l'activer directement depuis le programme lui-même.

Mais la fonction est maintenant en mémoire. Autant continuer à l'utiliser non ?

Vérifions que vous vous parvenez encore à prévoir le comportement des fonctions.

12° Vérifiez que la fonction est en mémoire. Tapez alors ceci dans la Console :

>>> calculer_moyenne(12, 14) 13.0 >>> calculer_moyenne(0, 14) 7.0 >>> resultat = calculer_moyenne(0, 14) >>> resultat 7.0

Question : comparer la déclaration de la fonction et l'appel calculer_moyenne(12, 14)

1
def calculer_moyenne(note1, note2):

Que contient la variable note2 lors de l'éxecution de cet appel ?

...CORRECTION...

Il suffit de comparer les places respectives des différents éléments lors de la déclaration et de l'appel.

1
def calculer_moyenne(note1, note2):
>>> calculer_moyenne(12, 14)

On voit donc que

  • 12 va être stocké dans note1 et
  • 14 va être stocké dans note2.

✎ 13° Compléter la fonction addition pour qu'elle fonctionne correctement. Enregistrer et lancer dans Thonny pour placer cette fonction en mémoire. En faire ensuite appel dans le shell pour vérifier son fonctionnement.

1 2 3 4 5 6 7 8 9
def addition(note1, note2): '''Renvoie la somme des deux notes :: param note1(int) :: une note dans [0;20] :: param note2(int) :: une note dans [0;20] :: return (int) :: la somme de note1 et note2 ''' return 0
>>> addition(12,14) 26 >>> resultat = addition(10,14) >>> resultat 24

✎ 14° Compléter la fonction multiplication pour qu'elle fonctionne correctement. Enregistrer et lancer dans Thonny pour placer cette fonction en mémoire. En faire ensuite appel dans le shell pour vérifier son fonctionnement.

1 2 3 4 5 6 7 8 9
def multiplication(x, y): '''Renvoie la multiplication de a par b :: param x(int) :: un entier :: param y(int) :: un entier :: return (int) :: x*y ''' return 0
>>> multiplication(5,10) 50 >>> resultat = multiplication(6,6) >>> resultat 36

4 - Au return, prêt, sortez !

Que se passe-t-il lorsque la fonction rencontre un return ?

A quel moment sort-on vraiment de la fonction ?

15° Observer le code suivant. On a demandé à quelqu'un de compléter la fonction suivante pour qu'elle réalise bien une division entière. Il a tapé ceci en oubliant de supprimer la ligne qu'on lui avait donné, celle avec le return 0.

1 2 3 4 5 6 7 8 9 10 11
def division(x, y): '''Renvoie la division entière de x par y :: param x(int) :: un entier :: param y(int) :: un entier NON NUL :: return (int) :: la division entière de x par y ''' return 0 mon_petit_calcul = x // y return mon_petit_calcul

Tester la fonction dans la console.

Question

Pourquoi cette fonction renvoie-t-elle TOUJOURS 0 ?

...CORRECTION...

On aurait pu croire que la fonction suit son cours et finit par répondre à la fin. Mais non !

Dès qu'on rencontre un return, la fonction renvoie ce qu'on a placé derrière et on sort immédiatement.

Dès qu'on arrive sur la ligne 9, on renvoie 0. Et on sort de la fonction.

Il ne sert strictement à rien de placer des choses sur des lignes qui suivent le return : ces lignes ne seront jamais analysées.

Ici, les lignes 10 et 11 ne servent strictement à rien. C'est comme si vous aviez tapé ceci :

1 2 3 4 5 6 7 8 9
def division(x, y): '''Renvoie la division entière de x par y :: param x(int) :: un entier :: param y(int) :: un entier NON NUL :: return (int) :: la division entière de x par y ''' return 0

5 - Et sans return ?

Lorsqu'on rencontre le return, on sort immédiatement. Ok.

Mais...

Et si on ne rencontrait jamais de return ? Que se passe-t-il ?

16° Observer le code suivant qui possède une fonction sans return...

1 2 3
def division(x, y): '''Calcule la division entière de x par y, mais n'en fait rien...''' mon_petit_calcul = x // y

Tester la fonction dans la console.

>>> division(7,2) >>>

Questions

  • Cette fonction renvoie-t-elle quelque chose ?

...CORRECTION...

Et non. Cette fonction ne renvoie rien. On a repris la main : nous sommes donc sortis de la fonction. Mais il n'y a eu AUCUN retour.

17° Observer un peu mieux l'onglet de Thonny après avoir tapé ceci dans la console :

Questions

  • Que contient la variable reponse ?
  • Quel est le type de cette variable ?
>>> reponse = division(5, 3) >>> reponse >>> type(reponse) ???
résultat d'une fonction sans retour

...CORRECTION...

En réalité, la variable contient quelque chose !

Elle contient None.

Quel est le type de None ?

>>> reponse = division(5, 3) >>> reponse >>> type(reponse) <class 'NoneType'>

Voilà comment on pourrait interpréter le code de la fameuse fonction qui ne possède pas de return.

1 2 3 4
def division(x, y): '''Calcule la division entière de x par y, mais n'en fait rien...''' mon_petit_calcul = x // y return None
Pas de fonction vraiment sans retour en Python...

On retiendra donc qu'une fonction Python renvoie au moins la valeur None lorsque son code se termine sans avoir rencontré un autre return.

En Python, on parle parfois de procédure pour désigner une fonction sans return. Elle renvoie au moins None, il ne s'agit donc pas vraiment d'une vraie procédure, mais l'idée est là.

6 - FAQ

J'ai entendu parler de routine, de procédure. C'est quoi ?

Le mot fonction est utilisé de façon assez générique dans Python. Par contre en informatique, il existe des entités qui peuvent être gérées de façon différente selon les langages.

Le vrai mot générique pour parler d'une suite d'instructions mémorisées et à laquelle on peut faire appel de nombreuses fois est le mot routine.

On distinguera deux types de routine :

  • Si la routine ne renvoie rien (pas de return), on parle de procédure.
  • Si la routine renvoie bien quelque chose vers le programme d'appel, on parle de fonction.

Du coup, les vraies procédures n'existent pas en Python : même si votre fonction ne renvoie rien, elle renvoie None. Cela permet de savoir que la fonction n'a rien renvoyé mais ce n'est pas vraiment ...rien... En effet, si la variable reponse existe et contient None, nous avons appris quelque chose : notre fonction est terminée.

C'est tout en terme de connaissances sur les fonctions pour aujourd'hui. Si on récapitule, nous avons vu :

  • Comment déclarer une fonction
  • Comment documenter un peu les fonctions
  • Comment une fonction parvient à renvoyer quelque chose avec le mot-clé return
  • Qu'on sort IMMEDIATEMENT de la fonction dès qu'on rencontre return
  • Qu'une fonction-python renvoie au moins None.

Activité publiée le 28 08 2019
Dernière modification : 26 10 2020
Auteur : ows. h.