Infoforall

Python 11 : LES FONCTIONS - LES BASES

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, le resize de Pillow sur les objets-image est une fonction, chr et ord sont des fonctions qui font le lien entre un caractère et sa valeur UNICODE...

Mais 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.

Commençons par vous montrer ce qu'on peut faire de très basique avec les fonctions :

animation d'introduction

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

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 :

1 - Premieres fonctions créées : les procédures

Une fonction est un ensemble d'instructions qui seront effectuées lorsqu'on va appeler la fonction. Aucune ligne de code de la fonction ne sera exécutée tant que la fonction n'aura pas été rendue active par son appel. Un petit exemple pour la forme. Il permet d'afficher les caractéristiques d'un personnage :

#!/usr/bin/env python

# -*- coding: utf-8 -*-


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -

def test_fonction() :

    print("--- Nom : Skywalker")

    print("--- Prénom : Luke")

    print("--- Profession : Jedi")

    input("--- Appuyez sur ENTREE")


# - - - - - - - - - - - - - - - - - -

# Corps du programme

# - - - - - - - - - - - - - - - - - -

print("Début du programme.")

print("Recherche d'informations :")

test_fonction()


print("Je suis sorti de la fonction.")

print("Nouvelle recherche d'informations :")

test_fonction()


print("Je suis encore sorti de la fonction.")

input("Appuyez sur ENTREE pour quitter")

CLIQUEZ ICI POUR VOIR L'ORDRE DES INSTRUCTIONS EXECUTEES :

01° Tester le bouton puis exécuter réellement le code. Que constatez-vous de nouveau avec d'aller plus loin ?

Comme on utilise la tabulation, n'oubliez pas d'indiquer à Notepad++ d'afficher les symboles spéciaux que sont le tabulations.

...CORRECTION...

On constate que les print au dessus du corps du programme (ceux avec print("---...") ne s'affichent pas dès le début.

Les lignes de code sous def test_fonction() : ne sont exécutées que si on tape test_fonction() dans le programme principal !

En plus, on constate qu'on peut exécuter plusieurs fois le code en tapant plusieurs fois test_fonction() et contrairement à une boucle, les exécutions ne se font pas nécessairement à la chaîne les unes des autres.

Et voici l'explication de ce programme ligne par ligne :

Les deux premières lignes sont habituelles : on précise qu'on travaille en Python puis on précise l'encodage des caractères du fichier-texte .py en lui-même.

#!/usr/bin/env python

# -*- coding: utf-8 -*-

Nous arrivons ensuite à une chose totalement nouvelle : la zone de déclaration des fonctions. On commence ici par la ligne def test_fonction(): où tous les éléments sont importants :

  1. def test_fonction(): : On commence par le mot-clé def qui indique qu'on va donner le nom d'une fonction.
  2. def test_fonction(): : On place un espace entre def et le nom.
  3. def test_fonction(): : On donne le nom de la fonction, test_fonction ici, suivi de parenthèses ().
  4. def test_fonction(): : On finit la déclaration du nom par les deux points : pour signaler que la suite va être composée des actions à effectuer (c'est le même principe qu'avec le if, le while, le for...)
  5. On tabule pour indiquer que l'instruction est incluse dans la fonction.
  6. La fin des instructions est indiquée par le fait qu'on revienne au même niveau que le texte def ... du départ.
  7. def test_fonction() :

        print("--- Nom : Skywalker")

        print("--- Prénom : Luke")

        print("--- Profession : Jedi")

        input("--- Appuyez sur ENTREE")

    <-- A partir d'ici, l'interpréteur comprend qu'il ne s'agit plus de test_fonction()

Le résultat attendu :

Début du programme.

Recherche d'informations :

--- Nom : Skywalker

--- Prénom : Luke

--- Profession : Jedi

--- Appuyez sur ENTREE

Je suis sorti de la fonction.

Nouvelle recherche d'informations :

--- Nom : Skywalker

--- Prénom : Luke

--- Profession : Jedi

--- Appuyez sur ENTREE

Je suis encore sorti de la fonction.

Appuyer sur ENTREE pour quitter

Point important : lorsque vous voulez utiliser la fonction, il ne faut pas juste donner son nom : il faut rajouter les parenthèses après son nom. Il faut donc utiliser test_fonction().

On peut donc utiliser de telles fonctions pour effectuer des tâches répétitives (et exactement identiques) qu'on devrait taper sinon à plusieurs endroits dans le code. On notera que si on devait les faire à la suite directe les unes des autres, les boucles FOR ou WHILE conviennent également.

Et si on veut faire des choses un peu différentes ? On peut aussi ?

Oui, on peut transmettre des arguments (des données) aux fonctions de façon à ce qu'elles utilisent ces contenus venant de l'extérieur. Lors de la déclaration de la fonction, il suffit de placer entre les parenthèses les variables nommées paramètres qui devront récupérer les arguments envoyés.

def test_fonction(sChaine1, sChaine2, sChaine3):

    print("--- Nom : "+sChaine1)

    print("--- Prénom : "+sChaine2)

    print("--- Profession : "+sChaine3)

    input("--- Appuyez sur ENTREE")

On devra maintenant fournir les données lors de l'appel de test_fonction : j'ai nommé mon premier paramètre sChaine1 car je veux que ce paramètre soit un String : je veux l'afficher. Si ce n'est pas un string, ça risque de poser problème. C'est pourquoi j'ai pris la peine de placer un s devant le nom : ça me sert de pense-bête.

Pour faire appel à la fonction dans le programme, il faut taper par exemple :

test_fonction("Yoda","Juste Yoda","Maitre Jedi, un peu vert.")

02° Modifier test_fonction comme ci-dessus et en faire l'appel deux fois avec des arguments (valeurs transmises) différents. Par exemple :

test_fonction("Yoda","Juste Yoda","Maitre Jedi, un peu vert.")

test_fonction("R2","D2","Un robot-meca")

...CORRECTION...

#!/usr/bin/env python

# -*- coding: utf-8 -*-


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -

def test_fonction(sChaine1, sChaine2, sChaine3) :

    print("--- Nom : "+sChaine1)

    print("--- Prénom : "+sChaine2)

    print("--- Profession : "+sChaine3)

    input("--- Appuyez sur ENTREE")


# - - - - - - - - - - - - - - - - - -

# Corps du programme

# - - - - - - - - - - - - - - - - - -

print("Début du programme.")

test_fonction("Yoda","Juste Yoda","Maitre Jedi, un peu vert.")

test_fonction("R2","D2","Un robot-meca")

input("Appuyez sur ENTREE pour quitter")

Alors, ça fonctionne comment ?

C'est relativement simple : lors du premier appel, on envoie les valeurs suivantes dans l'ordre :

  1. L'argument "Yoda" va donc être relié au paramètre de réception sChaine1.
  2. L'argument "Juste Yoda" va donc être relié au paramètre de réception sChaine2.
  3. L'argument "Maitre Jedi, un peu vert." va donc être relié au paramètre de réception sChaine3.

Vous avez ci-dessous une animation permettant de voir l'affectation successives des 3 paramètres (les 3 boites bleues) :

CLIQUEZ ICI POUR VOIR L'ORDRE DES INSTRUCTIONS EXECUTEES :

sChaine1 :

sChaine2 :

sChaine3 :

#!/usr/bin/env python

# -*- coding: utf-8 -*-


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -

def test_fonction(sChaine1, sChaine2, sChaine3) :

    print("--- Nom : "+sChaine1)

    print("--- Prénom : "+sChaine2)

    print("--- Profession : "+sChaine3)

    input("--- Appuyez sur ENTREE")


# - - - - - - - - - - - - - - - - - -

# Corps du programme

# - - - - - - - - - - - - - - - - - -

print("Début du programme.")

test_fonction("Yoda","Juste Yoda","Maitre Jedi, un peu vert.")

test_fonction("R2","D2","Un robot-meca")

input("Appuyez sur ENTREE pour quitter")

C'est donc comme si on avait tapé en début de fonction :

sChaine1 = "Yoda"

sChaine2 = "Juste Yoda"

sChaine3 = "Maitre Jedi, un peu vert."

Puis, ceci lors du deuxième appel :

sChaine1 = "R2"

sChaine2 = "D2"

sChaine3 = "Un robot-meca."

L'intérêt, c'est que cette affectation va se faire automatiquement en fonction des arguments fournis lors de l'apppel de la fonction.

03° Faire l'appel de test_fonction(8,"R2D2","Robot").

Vous devriez obtenir quelque chose comme :

Traceback (most recent call last):

File "G:\informatique\python\lec9_q3.py", line 16, in <module>

  test_fonction(8, "R2D2", "Robot")

File "G:\informatique\python\lec9_q3.py", line 8, in test_fonction

  print("--- Nom : "+sChaine1)

TypeError: Can't convert 'int' object to str implicitly

>>>

Le code utilisé est :

#!/usr/bin/env python

# -*- coding: utf-8 -*-


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -

def test_fonction(sChaine1, sChaine2, sChaine3):

    print("--- Nom : "+sChaine1)

    print("--- Prénom : "+sChaine2)

    print("--- Profession : "+sChaine3)

    input("--- Appuyez sur ENTREE")


# - - - - - - - - - - - - - - - - - -

# Corps du programme

# - - - - - - - - - - - - - - - - - -

test_fonction(8, "R2D2", "Robot")

input("Appuyer sur ENTREE pour quitter")

Donc, si vous voulez un code solide, il faudra penser à utiliser regulièrement les blocs try: expect: que nous avons vu lors de l'activité TANT QUE et FOR NOMINATIF.

04° Créer une fonction fois_trois(x) qui possède un seul paramètre et qui effectue print(3*x) avec la donnée(argument) fournie. Dans le corps du programme, en faire l'appel en donnant 10 puis "10" en paramètre.

Vous devriez voir que cette fois, votre fonction accepte plusieurs types de paramètres.

Voilà l'affichage que vous devriez obtenir :

30

101010

...CORRECTION...

#!/usr/bin/env python

# -*- coding: utf-8 -*-


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -

def fois_trois(x): # x est un paramètre

    print(3*x)


# - - - - - - - - - - - - - - - - - -

# Corps du programme

# - - - - - - - - - - - - - - - - - -

fois_trois(10) # 10 est un argument

fois_trois("10") # "10" est un argument

input("Appuyer sur ENTREE pour quitter")

05° On veut créer une fonction déclarée ainsi def affine(a,x,b): qui affiche le calcul suivant a*x+b à l'aide d'un print. Créer la fonction. En faire l'appel en utilisant affine(2,10,4). Que vaut a pendant l'appel ? x ? b ? Vous devriez obtenir et afficher 24 puisque 2*10+4 = 24.

...CORRECTION...

#!/usr/bin/env python

# -*- coding: utf-8 -*-


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -

def affine(a,x,b): # a,x et b sont les paramètres

    print(a*x+b)


# - - - - - - - - - - - - - - - - - -

# Corps du programme

# - - - - - - - - - - - - - - - - - -

affine(2,10,4) # 2, 10 et 4 sont des arguments

input("Appuyer sur ENTREE pour quitter")

06° Modifier le programme principal (mais pas votre définition de fonction), pour afficher les valeurs de f(x)= 2x+4 pour x variant de 1 à 3.

...CORRECTION...

#!/usr/bin/env python

# -*- coding: utf-8 -*-


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -

def affine(a,x,b): # a,x et b sont les paramètres

    print(a*x+b)


# - - - - - - - - - - - - - - - - - -

# Corps du programme

# - - - - - - - - - - - - - - - - - -

affine(2,1,4) # 2, 1 et 4 sont des arguments

affine(2,2,4) # 2, 2 et 4 sont des arguments

affine(2,3,4) # 2, 3 et 4 sont des arguments

07° Idem avec x variant de 1 à 100. Une boucle FOR sera nécessaire cette fois.

...CORRECTION...

#!/usr/bin/env python

# -*- coding: utf-8 -*-


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -

def affine(a,x,b): # a,x et b sont les paramètres

    print(a*x+b)


# - - - - - - - - - - - - - - - - - -

# Corps du programme

# - - - - - - - - - - - - - - - - - -

for x in range(1,101) :

    affine(2,x,4) # 2, x et 4 sont des arguments

2 - Le module Turtle

Pour illustrer visuellement l'intêret des fonctions, nous allons utiliser un nouveau module de Python : le module turtle qui permet de réaliser très facilement des dessins vectoriels.

08° Voilà un programme qui uilise turtle pour dessiner un trait de 50 pixels, tourner à droite à 90° puis tracer un second trait de 50 pixels.

#!/usr/bin/env python

# -*- coding: utf-8 -*-


import turtle as trt


dessin = trt.Turtle()

dessin.forward(50) # forward pour devant : on avance de 50

dessin.right(90) # right pour droite : on tourne à droite de 90°

dessin.forward(50)

09° Créer une fonction def carre(): qui permet de créer un carré.

Voici quelques autres méthodes qu'on peut appliquer aux objets de classe Turtle, qu'on crée à l'aide de mon_objet = turtle.Turtle().

Pour reculer : mon_objet.backward(50) permet de reculer de 50.

Pour tourner à gauche : mon_objet.left(45) permet de tourner de 45° à gauche.

Pour aller faire un mouvement linéaire jusqu'au point de coordonnées (x,y) : mon_objet.setpostion(x,y).

Pour faire un mouvement horizontal jusqu'à atteindre la valeur donnée en x : mon_objet.setx(x).

Pour faire un mouvement vertical jusqu'à atteindre la valeur donnée en y : mon_objet.sety(y).

Pour revenir au point d'origine : mon_objet.home().

Pour dessiner un cercle de rayon x : mon_objet.circle(x).

Pour dessiner un arc de cercle d'angle a et de rayon x : mon_objet.circle(x,a).

Pour tracer des polygones de "rayon" x possèdant y côtés : mon_objet.circle(x,360,y).

Pour placer un point de rayon x et de couleur précise : mon_objet.dot(x,"red").

Pour modifier la vitesse x, x variant de 1 à 10 : mon_objet.speed(x), x=0 veut dire pas d'animation.

Pour lever la pointe du crayon : mon_objet.penup().

Pour abaisser la pointe du crayon : mon_objet.pendown().

Pour avoir un mode RGB allant de 0 à 255 plutot que de 0.0 à 1.0 : trt.colormode(255).

Pour changer la couleur du crayon : mon_objet.pencolor("red") ou mon_objet.pencolor((200,100,50)).

Cela nous suffira mais vous pouvez aller voir la documentation Python pour voir ce que le module peut faire d'autre : PYTHON.

Voilà une solution possible pour la fonction carre :

#!/usr/bin/env python

# -*- coding: utf-8 -*-


import turtle as trt


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -

def carre():

    dessin.forward(50)

    dessin.right(90)

    dessin.forward(50)

    dessin.right(90)

    dessin.forward(50)

    dessin.right(90)

    dessin.forward(50)

    dessin.right(90)


# - - - - - - - - - - - - - - - - - -

# Corps du programme

# - - - - - - - - - - - - - - - - - -

dessin = trt.Turtle()

carre()

10° Créer une fonction avanceDe100 qui permet d'avancer de 100 sans rien dessiner. Utiliser ensuite cette fonction pour dessiner un carré, avancer de 100 sans dessiner et dessiner un second carré. Pensez à bien utiliser les différentes fonctions données ci-dessus. Remarque : ce sont des méthodes en réalité, ces fonctions ne peuvent s'appliquer qu'à des objets Turtle.

Les 3 carrés

11° Avec la méthode circle, créer une fonction cercle pour dessiner des cercles de 25 de rayon. Utiliser la fonction dans le programme principal pour aller au bon endroit (méthode setposition(x,y) ) et dessiner 3 cercles au dessus des 3 carrés.

Les 3 carrés

Pas mal avec quelques lignes de codes, non ? Comme c'est votre premier vrai contact avec la création de fonctions, voilà un corrigé possible :

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import turtle as trt


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -

def carre() :

    dessin.forward(50)

    dessin.right(90)

    dessin.forward(50)

    dessin.right(90)

    dessin.forward(50)

    dessin.right(90)

    dessin.forward(50)

    dessin.right(90)


def cercle() :

    dessin.circle(25)


def avanceDe100() :

    dessin.penup()

    dessin.forward(100)

    dessin.pendown()


def deplacement() :

    dessin.penup()

    dessin.setposition(25,-50)

    dessin.pendown()


# - - - - - - - - - - - - - - - - - -

# Corps du programme

# - - - - - - - - - - - - - - - - - -

dessin = trt.Turtle()

carre()

avanceDe100()

carre()

avanceDe100()

carre()

deplacement()

cercle()

avanceDe100()

cercle()

avanceDe100()

cercle()


input("Tapez sur ENTREE")

Mais, on peut encore faire mieux : on peut utiliser une fonction dans une autre fonction. Ainsi, je peux créer une fonction les3carres qui va contenir l'appel aux fonctions carre et avanceDe100.

12° Tester le code suivant puis compléter la fonction les3cercles pour que le programme donne le même résultat que précédemment.

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import turtle as trt


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -

def carre() :

    dessin.forward(50)

    dessin.right(90)

    dessin.forward(50)

    dessin.right(90)

    dessin.forward(50)

    dessin.right(90)

    dessin.forward(50)

    dessin.right(90)


def cercle() :

    dessin.circle(25)


def avanceDe100() :

    dessin.penup()

    dessin.forward(100)

    dessin.pendown()


def deplacement() :

    dessin.penup()

    dessin.setposition(25,-50)

    dessin.pendown()


def les3carres() :

    carre()

    avanceDe100()

    carre()

    avanceDe100()

    carre()


def les3cercles() :

    print("A COMPLETER")


# - - - - - - - - - - - - - - - - - -

# Programme principal

# - - - - - - - - - - - - - - - - - -

dessin = trt.Turtle()

les3carres()

deplacement()

les3cercles()


input("Tapez sur ENTREE")

13° Modifier les codes des fonctions carre et cercle qui seront transformées en fonction avec paramètre : carre(longueur) et cercle(rayon) où longueur et rayon seront les paramètres du côté du carré ou de rayon du cercle. Créez des carrés de côté 25, 35 et 45. Idem pour les rayons des cercles.

...CORRECTION...

def carre(longueur) :

    dessin.forward(longueur)

    dessin.right(90)

    dessin.forward(longueur)

    dessin.right(90)

    dessin.forward(longueur)

    dessin.right(90)

    dessin.forward(longueur)

    dessin.right(90)


def les3carres() :

    carre(50)

    avanceDe100()

    carre(50)

    avanceDe100()

    carre(50)


14° Modifier le code de la fonction carre en utilisant une boucle FOR plutôt que de demander quatre fois la même chose en le tapant manuellement.

...CORRECTION...

def carre(longueur) :

    for i in range (4) :

        dessin.forward(longueur)

        dessin.right(90)


Vous pouvez constater que le résultat est le même après modification. C'est la force des fonctions : lorsqu'on les utilise, on doit simplement savoir quels arguments transmettre et avoir une idée du but de la fonction.

Vous n'avez aucunement besoin de connaitre les rouages internes d'une fonction ou d'une méthode pour l'utiliser. Elle peut contenir un code simple ou compliqué sans que vous ayez à vous en soucier. Sauf si c'est vous que l'avez conçue bien entendu.

Fonctions, procédures et méthodes

Voilà la limite des "fonctions basiques" : on ne peut pas utiliser leurs codes pour faire autre chose. Avec votre fonction affine, on ne peut pas récupérer le 24 et refaire un calcul avec lui. Il s'agit uniquement d'un affichage console. Comment faire pour récupérer le résultat ? Et bien, il faut rajouter une ligne de code qui va renvoyer quelque chose vers le programme d'appel.

Comme la fonction ne renvoie ni information ni valeur vers le programme principal, on pourrait la nommmer PROCEDURE.

procédure

Si on parvient à faire communiquer la fonction, on la nommera effectivement FONCTION.

procédure

Dans certains langages, fonctions et procédures ne se déclarent pas de la même manière. Ce n'est pas le cas de Python. C'est donc la dernière fois que nous noterons ici le mot procédure.

Et les méthodes ? Il s'agit tout simplement du nom qu'on donne à une fonction appartenant à une classe d'objets et pouvant donc agir sur un objet. La plupart du temps, elles sont utilisées sous la forme objet.methode(argument). Vous vous souvenez ?

Nous avons donc vu les fonctions sans retour : les procédures.

Il nous reste à voir les fonctions renvoyant une information vers le programme qui en ont fait l'appel.

3 - Fonctions avec retour d'information

Pour renvoyer ce que pointe une variable reponse dans la partie de code qui a fait appel à la fonction, il suffit d'utiliser le code suivant return reponse si reponse = a*x+b. Mais on pourrait même faire plus court en utilisant directement return a*x+b

#!/usr/bin/env python

# -*- coding: utf-8 -*-


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions #

# - - - - - - - - - - - - - - - - - -

def affine(a,x,b) :

    y = a*x+b

    return y


# - - - - - - - - - - - - - - - - - -

# Corps du programme #

# - - - - - - - - - - - - - - - - - -

f1 = affine(2,10,4)

print(f1)

input("Appuyer sur ENTREE pour quitter")

Comme vous le voyez, on stocke le résultat de la fonction (qu'elle renvoie avec le return) dans une variable f1 pour garder le résultat en mémoire.

CLIQUEZ ICI POUR VOIR LE CONTENU DES VARIABLES :

Variables y, a, x et y de la fonction :

y :

a :

x :

b :

Variable f du programme principal :

f1 :

15° Avant d'utiliser le code, tentez de découvrir ce que doit afficher normalement le code print(f1).

...CORRECTION...

On voit qu'on veut stocker dans f1 le résultat de la fonction affine(2,10,4).

Lors de l'appel, on a donc a = 2, x = 10 et b = 4.

La fonction va alors stocker dans y le résultat du calcul 2*10+4, soit 24.

Le return fait référence à y et, de retour dans le programme principal, f1 contiendra 24.

ATTENTION : lorsque la fonction rencontre return, elle calcule le résultat et sort ensuite du codage de la fonction : c'est comme un break : le reste du code ne sera pas analysé.

On peut également donner le contenu d'une variable comme argument : vous n'êtes pas obligé de donner une valeur en "dur" ce qui est très pratique.

16° Et ce code, que renvoie-t-il ? Faire le calcul à la main puis lancer le programme pour vérifier.

#!/usr/bin/env python

# -*- coding: utf-8 -*-


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions #

# - - - - - - - - - - - - - - - - - -

def affine(a,x,b) :

    y = a*x+b

    return y


# - - - - - - - - - - - - - - - - - -

# Corps du programme #

# - - - - - - - - - - - - - - - - - -

f1 = affine(2,3,4)

f2 = affine(2,f1,4)

print(f1)

print(f2)

input("Appuyer sur ENTREE pour quitter")

...CORRECTION...

f1 va contenir le retour de la fonction affine(2,3,4), donc 2*3+4, soit 10.


f2 va contenir le retour de la fonction affine(2,f1,4)

Comme la variable f1 fait référence à l'integer 10, le paramètre x de la fonction affine va recevoir 10.

On calcule donc 2*10+4, soit 24.

4 - Importation de modules de fonctions

Nous avons déjà vu de nombreuses bibliothèques (ou modules). Par les importer, il suffit d'utiliser l'instruction import :

Pour voir toutes les fonctions de la bibliothèque math : DOC PYTHON

Bon, alors autant toujours utiliser, from XXX import * si cela évite d'écrire un truc en plus à chaque fois qu'on utilise une fonction ?

Non. Si vous n'importez qu'un seul module, vous pouvez faire un import total et complet, oui.

Mais si vous faites cela avec deux, trois ou quatre modules, les chances sont grandes qu'ils possèdent des fonctions qui portent le même nom. Et là, bonne chance pour retrouver la bonne !

A titre d'exemple, voici un code qui vous permet d'estimer le temps nécessaire à un ensemble de calcul.

Il intègre le module time et utilise la fonction time qui va permettre d'obtenir le temps écoulé depuis le temps zéro de l'ordinateur (certainement le 1er janvier 1970 à 00h00). Il suffit de stocker le temps initial au commencement d'un calcul et le temps final après calcul et nous aurons la durée du calcul.

#!/usr/bin/env python

# -*- coding: utf-8 -*-

from time import time


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions #

# - - - - - - - - - - - - - - - - - -

def foisDeux(entree) :

    reponse = entree*2

    return reponse


# - - - - - - - - - - - - - - - - - -

# Corps du programme #

# - - - - - - - - - - - - - - - - - -


valeur = float(input("Valeur initiale : "))

t0 = time() # On stocke le temps initial avant les différents calculs


for i in range(101) :

    print("Le terme de rang ",i," = ",valeur)

    valeur = foisDeux(valeur)


tf = time() # On stocke le temps final après les différents calculs

duree = tf-t0


print("Temps écoulé lors du calcul : ",duree," s")

input("Appuyer sur ENTREE")

17° Tester le programme ci-dessus. Faire varier le nombre de calculs pour voir l'évolution du temps de calculs avec le nombre de calculs. Vous devriez parvenir à faire cela sans savoir ce que fait exactement la fonction time, c'est l'avantage de tout ceci : on importe et on utilise.

5 - Mini-projet : Des fonctions pour Simon

Nous allons reprendre notre jeu de Simon en lui rajoutant une fonctionnalité : nous voudrions faire briller les carrés lorsqu'on clique dessus.

interface Simon

Commençons par donner le code permettant d'obtenir l'interface (voir la fin de l'activité sur Tkinter) :

# -*-coding:Utf-8 -*

from tkinter import *

from PIL import Image as Img

from PIL import ImageTk


# - - - - - - - - - - - - - - - - - -

# Déclarations des fonctions

# - - - - - - - - - - - - - - - - - -


fen_princ = Tk()

fen_princ.geometry("500x500")


# Création des images de base


carreBleu = Img.new("RGB", (100,100), (0,0,200))

carreBleuTk = ImageTk.PhotoImage(carreBleu)


carreVert = Img.new("RGB", (100,100), (0,200,0))

carreVertTk = ImageTk.PhotoImage(carreVert)


carreRouge = Img.new("RGB", (100,100), (200,0,0))

carreRougeTk = ImageTk.PhotoImage(carreRouge)


carreJaune = Img.new("RGB", (100,100), (200,200,0))

carreJauneTk = ImageTk.PhotoImage(carreJaune)


# Création et placement des widget Label


imageA = Label(fen_princ, image = carreBleuTk)

imageA.place(x = 100, y = 100)


imageB = Label(fen_princ, image = carreVertTk)

imageB.place(x = 300, y = 100)


imageC = Label(fen_princ, image = carreRougeTk)

imageC.place(x = 100, y = 300)


imageD = Label(fen_princ, image = carreJauneTk)

imageD.place(x = 300, y = 300)


# - - - - - - - - - - - - - - - - - -

# Bouclage de la fenêtre fen_princ

# - - - - - - - - - - - - - - - - - -


fen_princ.mainloop()

Pour rappel (voir la fin de l'activité Tkinter) :

18° Tester cette interface visuelle.

Nous avons revu les méthodes geometry et place.

Il nous reste à voir comment changer la couleur des carrés lorsqu'on clique dessus...

Pour cela, nous allons devoir créer un détecteur d'événement :

Nous allons rajouter ceci avant la boucle de surveillance de fin :

# - - - - - - - - - - - - - - - - - -

# Gestion des événements

# - - - - - - - - - - - - - - - - - -


imageA.bind( '<Button-1>', changeA )

imageA.bind( '<ButtonRelease-1>', retourA )

Vous verrez l'explication précise de ce code dans l'activité GESTION DES EVENEMENTS.

Si on résume, on crée avec la méthode bind deux événements liés au fait d'appuyer sur le bouton de la souris sur imageA ou de relacher le bouton.

On constate que cela devrait lancer l'appel de deux fonctions : changeA et retourA. Il reste donc à les définir :

# - - - - - - - - - - - - - - - - - -

# Déclaration des fonctions

# - - - - - - - - - - - - - - - - - -


def changeA(event) :

    imageA.configure(image = carreBleuTk2)


def retourA(event) :

    imageA.configure(image = carreBleuTk)

Comme vous pouvez le voir, il s'agit de deux fonctions très simples qui ne font que changer l'image contenue dans le Label en utilisant la méthode configure. La seule chose étrange est la présence obligatoire de la variable event. Nous verrons à quoi elle sert pendant l'activité sur les événements. Pour l'instant, sachez simplement qu'on doit la placer là sous peine de déclencher une erreur.

19° Rajouter tout ceci dans votre propre code (sans oublier de créer l'image ImgTk nommée carreBleuTk2 dans le corps du programme) et lancer le programme pour voir s'il fonctionne.

Voici un visuel de ce que vous devriez obtenir (le carré bleue est un peu plus clair) :

interface Simon interactif

Et le code correspondant (au cas où vous seriez bloqué sur un point particulier) :

# -*-coding:Utf-8 -*

from tkinter import *

from PIL import Image as Img

from PIL import ImageTk


# - - - - - - - - - - - - - - - - - -

# Déclaration des fonctions

# - - - - - - - - - - - - - - - - - -


def changeA(event) :

    imageA.configure(image = carreBleuTk2)


def retourA(event) :

    imageA.configure(image = carreBleuTk)


# - - - - - - - - - - - - - - - - - -

# Création de la fenêtre et des objets associés la fenêtre

# - - - - - - - - - - - - - - - - - -


fen_princ = Tk()

fen_princ.geometry("500x500")


# Création des images de base


carreBleu = Img.new("RGB", (100,100), (0,0,200))

carreBleuTk = ImageTk.PhotoImage(carreBleu)


carreVert = Img.new("RGB", (100,100), (0,200,0))

carreVertTk = ImageTk.PhotoImage(carreVert)


carreRouge = Img.new("RGB", (100,100), (200,0,0))

carreRougeTk = ImageTk.PhotoImage(carreRouge)


carreJaune = Img.new("RGB", (100,100), (200,200,0))

carreJauneTk = ImageTk.PhotoImage(carreJaune)


carreBleu2 = Img.new("RGB", (100,100), (75,75,250))

carreBleuTk2 = ImageTk.PhotoImage(carreBleu2)


# Création et placement des widget Label


imageA = Label(fen_princ, image = carreBleuTk)

imageA.place(x = 100, y = 100)


imageB = Label(fen_princ, image = carreVertTk)

imageB.place(x = 300, y = 100)


imageC = Label(fen_princ, image = carreRougeTk)

imageC.place(x = 100, y = 300)


imageD = Label(fen_princ , image = carreJauneTk)

imageD.place(x = 300, y = 300)


# - - - - - - - - - - - - - - - - - -

# Gestion des événements

# - - - - - - - - - - - - - - - - - -


imageA.bind( '<Button-1>', changeA )

imageA.bind( '<ButtonRelease-1>', retourA )


# - - - - - - - - - - - - - - - - - -

# Bouclage de la fenêtre fen_princ

# - - - - - - - - - - - - - - - - - -


fen_princ.mainloop()

20° Rajouter les lignes nécessaires pour obtenir le même effet sur les 4 carrés colorés.

Voilà. Nous verrons comment gérer cela de façon plus automatisée lors de l'activité sur les événements mais vous avez désormais de quoi vous amusez. Les leçons suivantes traitent désormais de choses plus ou moins indépendantes.

Vous avez vu les notions fondamentales pour gérer la plupart des choses :

  • Les variables (et la couleur spécifique aux variables faisant références à un widget)
  • Les tests logiques et les boucles
  • Les fonctions et les fonction internes aux objets, les méthodes
  • Les listes permettant d'avoir une structure de données mutable.
  • Les bibliothèques Pillow et tkinter

C'est tout pour cette fois. Nous verrons plus tard qu'on peut omettre de déclarer certains arguments d'une fonction (on peut définir des valeurs par défauts), qu'on peut donner des noms aux paramètres et plus encore. Mais rien qu'avec cette simple nouvelle notion de fonction vous avez de quoi multiplier par 10 les possibilités de vos codes.

L'activité suivante est une activité complémentaire à celle-ci : on y traite de la portée des variables dans les fonctions.

Voici la correction de la petite interface au cas où vous bloqueriez (cette solution n'intègre pas les outils non encore vus qui permettront de ne pas écrire 4 fois la même chose puisqu'il y a 4 carrés) :

# -*-coding:Utf-8 -*

from tkinter import *

from PIL import Image as Img

from PIL import ImageTk


# - - - - - - - - - - - - - - - - - -

# Déclaration des fonctions

# - - - - - - - - - - - - - - - - - -


def changeA(event) :

    imageA.configure(image = carreBleuTk2)


def retourA(event) :

    imageA.configure(image = carreBleuTk)


def changeB(event) :

    imageB.configure(image = carreVertTk2)


def retourB(event) :

    imageB.configure(image = carreVertTk)


def changeC(event) :

    imageC.configure(image = carreRougeTk2)


def retourC(event) :

    imageC.configure(image = carreRougeTk)


def changeD(event) :

    imageD.configure(image = carreJauneTk2)


def retourD(event) :

    imageD.configure(image = carreJauneTk)


# - - - - - - - - - - - - - - - - - -

# Création de la fenêtre et des objets associés la fenêtre

# - - - - - - - - - - - - - - - - - -


fen_princ = Tk()

fen_princ.geometry("500x500")


# Création des images de base


carreBleu = Img.new("RGB", (100,100), (0,0,200))

carreBleuTk = ImageTk.PhotoImage(carreBleu)


carreVert = Img.new("RGB", (100,100), (0,200,0))

carreVertTk = ImageTk.PhotoImage(carreVert)


carreRouge = Img.new("RGB", (100,100), (200,0,0))

carreRougeTk = ImageTk.PhotoImage(carreRouge)


carreJaune = Img.new("RGB", (100,100), (200,200,0))

carreJauneTk = ImageTk.PhotoImage(carreJaune)


carreBleu2 = Img.new("RGB", (100,100), (75,75,250))

carreBleuTk2 = ImageTk.PhotoImage(carreBleu2)


carreVert2 = Img.new("RGB", (100,100), (75,250,75))

carreVertTk2 = ImageTk.PhotoImage(carreVert2)


carreRouge2 = Img.new("RGB", (100,100), (250,75,75))

carreRougeTk2 = ImageTk.PhotoImage(carreRouge2)


carreJaune2 = Img.new("RGB", (100,100), (250,250,0))

carreJauneTk2 = ImageTk.PhotoImage(carreJaune2)


# Création et placement des widget Label


imageA = Label(fen_princ, image = carreBleuTk)

imageA.place(x = 100, y = 100)


imageB = Label(fen_princ, image = carreVertTk)

imageB.place(x = 300, y = 100)


imageC = Label(fen_princ, image = carreRougeTk)

imageC.place(x = 100, y = 300)


imageD = Label(fen_princ , image = carreJauneTk)

imageD.place(x = 300, y = 300)


# - - - - - - - - - - - - - - - - - -

# Gestion des événements

# - - - - - - - - - - - - - - - - - -


imageA.bind( '<Button-1>', changeA )

imageB.bind( '<Button-1>', changeB )

imageC.bind( '<Button-1>', changeC )

imageD.bind( '<Button-1>', changeD )


imageA.bind( '<ButtonRelease-1>', retourA )

imageB.bind( '<ButtonRelease-1>', retourB )

imageC.bind( '<ButtonRelease-1>', retourC )

imageD.bind( '<ButtonRelease-1>', retourD )


# - - - - - - - - - - - - - - - - - -

# Bouclage de la fenêtre fen_princ

# - - - - - - - - - - - - - - - - - -


fen_princ.mainloop()