Accueil

Fonctions (et procédures)

Objectifs du TD : apprendre à décomposer et à réutiliser le code en écrivant des fonctions

Vous avez utilisé à plusieurs reprises des fonctions comme la fonction print ou la fonction input. Ces fonctions sont des fonctions prédéfinies du langage. Comme en mathématiques, une fonction a des arguments (appelés paramètres en informatique), et effectue des calculs. Python possède des fonctions prédéfinies dans le coeur du langage, mais aussi des fonctions qui sont définies dans des modules spécifiques qu'il faut importer, comme la fonction randint du module random qui sert à tirer un nombre entier aléatoire.
Dans ce TD, vous allez écrire vos propres fonctions. Cela est très utile pour décomposer les problèmse et répéter plusieurs fois le même traitement à des données différentes.

EXERCICES DE COURS

1. Les fonctions

L'utilisation des fonctions dans un langage de programmation est similaire à celle des fonctions en mathématiques: il y a la définition de la fonction et l'utilisation de la fonction. Par exemple, on peut définir une fonction affine f(a,b,x)= a*x+b et l'utiliser pour calculer 3*f(2,3,8)+1.

Définition d'une fonction
La syntaxe de la définition d'une fonction est la suivante :
   def nom_de_la_fonction(parametre_1,...,parametre_n) :
       code_de_la_fonction
       return valeur_calculée
L'interprèteur Python lit le programme instructions après instructions. Quand il tombe sur le mot clé def il stocke en mémoire la définition de la fonction jusqu'à sa dernière ligne.
Quand il trouve une instruction contenant le nom de la fonction qui a été définie, il utilise la définition de la fonction, on dit qu'il effectue un appel de fonction.
Voici par exemple la définition d'une fonction affine et plusieurs utilisations de cette fonction.

# exemple d'une fonction affine

def affine(a,b,x) :
    return a*x+b
# fin de la fonction

# début du programme

# deux exemples d'appels
r = affine(3,4,8))
print(r+2*affine(1,1,1))

# boucle pour afficher tous les couples entre 1 et 10
# de la fonction affine 3x+5
print("points de la fonctions affine 3x+5") 
x = 1
while x <=10 :
    print(x,affine(3,5,x))
    x=x+1

Explications : appel de fonction
Quand l'interprète Python exécute la ligne r=affine(3,4,8), il fait un appel de fonction :
  1. il vérifie que la fonction affine existe et il vérifie qu'on lui a fourni le bon nombre de paramètres (3 ici),
  2. il substitue les paramètres de la fonction (a,b et x) avec leur valeur d'appel (3,4 et 8). Plus précisément, (a,b,x) sont les paramètres formels de la fonction affine et (3,4,8) sont les paramètres effectifs de l'appel de la fonction.
  3. il exécute le code de la fonction jusqu'au return
  4. il renvoie le calcul (ici 3*8+4). Puisqu'on a écrit r=affine(3,4,8) le résultat du calcul est mis dans la variable r
De la même façon, la boucle while effectue 10 appels de la fonction affine avec a et b fixés à 3 et 5, et avec x qui varie de 1 à 10.

A RESPECTER
Les programmes que vous allez écrire à partir de maintenant vont être de plus en plus complexes. Afin de ne pas introduire des erreurs de programmation, vous devez impérativement respecter la structure suivante pour vos fichiers .py (les points suivis de * sont facultatifs):
  1. Commentaire décrivant les fonctionnalités du programme
  2. Import nécessaires *
  3. Déclaration des fonctions
  4. Programme principal avec :
    1. Définition de constantes
    2. Définition des variables du programme, lecture de données (via la fonction input)
    3. Instructions du programme principal avec appel des fonctions
    4. Affichage des résultats (via la fonction print)
Ne pas respecter cette structure sera sanctionné dans les évaluations.

Exercices

  1. Utiliser la fonction affine dans un programme de conversion entre degré Celsius et degré Fahrenheit sachant que : T(°C) = (T(°F) - 32)/1.8 et T(°F) = T(°C)×1.8 + 32 . Le programme demande la température et demande l'unité (Celsius ou Fahrenheit) et il affiche la valeur convertie. Pour vérifier vos résultats, vous pouvez aller sur http://www.le-convertisseur.com/conversion-temperature.html

  2. Définir les fonctions perimetre et aire qui renvoient le perimétre et l'aire d'un cercle dont le rayon est donné en paramétre. Utilisez ces fonctions dans un programme qui demande à l'utilisateur un rayon initial rayonInit et un nombre d'itérations. A l'itération i, le programme affiche le périmétre et l'aire du cercle de rayon rayonInit + 100*i.
    Indications :
    Rayon initial ? 124
    nombre d'itérations ? 5
    Rayon : 124.0 , perimétre : 779.1149780902687 , aire : 48305.12864159666
    Rayon : 224.0 , perimétre : 1407.4335088082273 , aire : 157632.55298652145
    Rayon : 324.0 , perimétre : 2035.7520395261859 , aire : 329791.83040324214
    Rayon : 424.0 , perimétre : 2664.0705702441446 , aire : 564782.9608917587
    Rayon : 524.0 , perimétre : 3292.3891009621034 , aire : 862605.944452071
    

Une fonction doit retourner une valeur pour tous les cas possibles de son exécution. Sauver l'exemple suivant dans un fichier et exécutez-le pour val=50 et val=-1. Que se passe-t-il ?
def bizare(v):
   if v>=30:
      print("cas 1")
      return 30
   else :
      if v>=0:
         print("cas 2")
         return 0
      else :
         print("cas 3")

# programme principal
val = int(input("un entier "))
v = bizare(val)
print(v*3)


2. Les procédures

Les fonctions que vous avez écrites ci-dessus font un calcul et renvoient un résultat. Elles sont utiles pour structurer le code en décomposant les étapes de calcul; ceci est indispensable quand on écrit des gros programmes.
Il peut aussi être utile de structurer le code en écrivant des procédures qui font des actions mais ne renvoient pas de résultat. La différence est simplement qu'elles ne se terminent pas par return.
  1. Ecrire une procédure dessinePolygone qui dessine un polygone régulier. Les paramètres sont le nombre de cotés, la longueur d'un coté, le point en bas à gauche du polygone, la couleur du polygone. Utilisez cette procédure dans un programme qui affiche un carré bleu et un octogone rouge.

  2. Une fonction ou procédure peut appeler une autre fonction ou procédure. Par exemple, voici un code qui définit la procédure dessineCarre :
    # un carré est un polygone particulier : la procédure "dessineCarre" appelle
    # la procédure "dessinePolygone"
    
    # dessine un carré de largeur "cote", de couleur "couleur" dont le point
    # en bas à gauche est en (x,y)	    
    def dessineCarre(cote,x,y,couleur):
        dessinePolygone(4,cote,x,y,couleur)
    
    Définissez de la même façon les fonctions dessineTriangle et dessineCercle. Tester vos procédures en dessinant quelques carrés, cercles et triangles.

  3. Reprenez votre code de la table de multiplication générale (i.e. où l'on peut dire quelle table on veut réviser et jusqu'à quel rang) et transformez-le en une procédure. Ecrivez un code qui fait une boucle où l'on demande à l'utilisateur quelle table il veut réviser et jusqu'à quel rang, puis qui demande s'il veut continuer. Exemple de trace d'exécution :
    Révision des tables de multiplication
    
    Quelle table voulez-vous réviser ? 3
    Jusqu'à quel rang ? 4
    ***************************
    révision de la table de 3 jusqu'à 4
    1 fois 3  : 3
    2 fois 3  : 6
    3 fois 3  : 9
    4 fois 3  : 12
    ***************************
    Encore ? (o/n) o
    
    Quelle table voulez-vous réviser ? 2
    Jusqu'à quel rang ? 5
    ***************************
    révision de la table de 2 jusqu'à 5
    1 fois 2  : 2
    2 fois 2  : 4
    3 fois 2  : 6
    4 fois 2  : 8
    5 fois 2  : 10
    ***************************
    Encore ? (o/n) n
    
    fin de la révision
    
  4. En utilisant la procédure dessinePolygone écrire un programme qui trace une ligne de carrés de taille croissante en allant de gauche à droite. La taille du côté du premier carré, le facteur d'accroissement et le nombre de carés sont lus au clavier. La ligne commence au point de coordonnées (-300,0). Vous n'avez PAS à traiter le problème de sortie de la fenêtre turtle dans le cas où il y a trop de carrés à dessiner. Exemple du dessin obtenu pour une longueur initiale de 50, un facteur d'accroissement de 1.5 et 5 carrés :

Complément : variables locales et globales
Les variables qui sont utilisées dans la définition d'une fonction sont appelées des variables locales. Par exemple, les variables angle et longueurCote sont des variables locales à la fonction dessinePolygone. Les variables locales ne sont visibles qu'à l'intérieur de la fonction, et elles masquent les autres variables de même nom. Par exemple:
# exemple pour illustrer la notion de variable locale
def masque():
   largeur = 40
   return 2*largeur

#programme principal
largeur = 3
print("résultat fonction :",masque(),", variable largeur :",largeur)
 
Le résultat d'exécution est le suivant:
résultat fonction : 80 , variable largeur : 3
Il y a deux variables largeur dans ce code. La variable qui est déclarée dans la fonction masque est locale à la fonction masque c'est à dire qu'elle n'est accessible que dans cette fonction. Quand on exécute la fonction masque, cette variable locale prend la valeur 40. Elle est utilisée pour calculer la valeur renvoyée par la fonction, c'est à dire 80. Mais cela ne modifie en rien la variable largeur qui a été définie dans le programme principal, qui a toujours la valeur 3.
Par opposition, les variables définies dans le programme principal sont des variables globales du programme (comme ici la variable largeur qui a été définie dans le programme principal).

3. Valeurs par défaut des paramètres

Une des particularités du langage Python est qu'il permet de définir très simplement les valeurs par défaut de certains paramètres. Par exemple, voici les valeurs par défaut de la fonction print.

Valeurs par défaut de la fonction print
La syntaxe détaillée de la fonction print est la suivante :
       print(val1,val2,...,valn,sep=' ',end='\n',file=sys.stdout)
val1,val2,...,valn sont les valeurs à afficher.
sep est le séparateur; par défaut c'est un espace.
end est le caractère de fin; par défaut c'est le caractère \n qui permet de passer à la ligne.
file indique l'endroit où il faut écrire; par défaut c'est sys.stdout qui représente la sortie standard c'est à dire votre écran. Nous verrons plus tard qu'on peut aussi écrire dans des fichiers.
Le code suivant :
print("a","b",sep="",end="")
print("c","d",sep="",end="")
affiche :
abcd
puisqu'on a dit avec sep="" que les valeurs sont séparées par rien, et avec end="" que la fin de ligne est vide c'est à dire que l'on ne passe pas à la ligne.
Le code suivant :
i=0
while i<3:
    print(i,sep="",end="")
    i=i+1
affiche :
012
Vous pouvez vous aussi donner des valeurs par défaut à certains paramètres des fonctions que vous définissez. Il suffit tout simplement de donner la valeur par défaut à l'endroit où vous définissez le paramètre. Voici une fonction dessineCarre qui a un paramètre par défaut qui fixe la couleur à rouge :
from turtle import *

# dessine un carré de côté l, de couleur c
# par défaut la couleur est "red"
def carre(l,c="red"):
    color(c)
    angle = 90
    # dessin des 4 côtés
    k=0
    while k<4:
        left(angle)
        forward(l)
        k=k+1

# programme de test
# dessine un carré rouge
carre(100)
# dessine un carré bleu
carre(200,"blue")

Les paramètres par défaut doivent être les derniers paramètres de la fonction (i.e. on ne peut pas écrire carre(c="red",l))

Exercices

  1. Modifier votre fonction dessinePolygone pour que la valeur par défaut de la couleur soit "blue" et que le point de départ soit (0,0).

  2. Modifier votre fonction tableMultiplication pour que la valeur par défaut du rang jusqu'auquel on récite la table soit 10.