fonctions Evénement

Identification

Infoforall

20 - Interface et variables globales


Nous avons vu dans l'activité précédente qu'il existe deux types de variables.

  1. les variables locales sont les variables déclarées dans une fonction.. Elles ne peuvent être lues et modifiées qu'à l'intérieur de leur fonction puisqu'elles n'existent que le temps de son exécution.
  2. portee-variable-locale
  3. les variables globales sont les variables qui sont créées directement dans le corps du programme.
  4. portee-variable-globale

En application directe, nous réaliserons aujourd'hui une interface graphique événementielle avec tkinter, utilisant fonctions et variables globales.

En effet, le problème est, qu'avec l'interface Tkinter, on ne peut donner que des noms de fonctions (sans pouvoir fournir de paramètres donc) lorsqu'on veut créer une action sur un clic ou autre.

truc_a_cliquer.bind('<Button-1>', modifier)

L'une des façons de régler cela : les variables globales. Mais souvenez-vous : ce n'est pas bien.

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

Evaluation ✎ : 07 à faire valider en classe (à part la notion d'interface, de capteurs et d'actionneurs, aucune connaissance ici ne fait pas partie du programme officiel, mais savoir créer une (petite) interface graphique est plutôt agréable)

Documents de cours : open document ou pdf

ATTENTION : utiliser les variables globales n'est pas vraiment une bonne pratique. Ici, c'est juste pour contourner la façon dont Tkinter demande de gérer les événements.

On pourrait d'ailleurs gérer cela proprement mais vous n'avez pas encore les connaissances permettant de le faire.

1 - Application aux interfaces graphiques

Interface graphique ou textuelle

Lorsqu'on crée un programme, on aime bien qu'il puisse interagir avec l'utilisateur.

Deux mondes coexistent donc :

  • D'un côté, le monde physique dans lequel l'utilisateur peut agir sur l'ordinateur et voir l'écran par exemple.
  • De l'autre côté, le programme qui tourne à l'intérieur de l'ordinateur

Pourtant, une interaction entre les deux mondes est possible. Ce point d'interaction se nomme

  • une interface graphique si on peut s'y déplacer avec la souris
  • une interface textuelle si l'interactivité se limite à l'utilisation du clavier (on parle alors de console ou de terminal)

Les interactions se font dans les deux sens :

  • L'utilisateur peut transmettre des informations au programme en passant par l'interface
  • Le programme peut transmettre des informations à l'utilisateur en passant par l'interface.

Cette interface est capable de faire le lien entre le monde extérieur et le code informatique interne.

L'interface graphique est donc composée d'un ensemble de programmes préexistants au votre.

Pour cela, elle a besoin de communiquer avec les composants matériels qui permettent à l'utilisateur de transmettre ou recevoir des informations de l'utilisateur.

Capteurs et actionneurs

Définitions

  • Un capteur est un composant capable de transmettre une information issue du monde physique en signal électronique ou informatique.
  • Grandeur physique  >>>    CAPTEUR     >>> 
    Valeur numérique
  • Un actionneur est un composant capable de provoquer à partir d'un signal électronique une action réelle dans le monde physique
  • Grandeur physique  <<<   ACTIONNEUR   <<< 
    Valeur numérique

01° Classer les trois composants visibles (écran, clavier, souris) en les mettant

  • soit dans la catégorie des capteurs,
  • soit dans la catégorie des actionneurs.

...CORRECTION...

La souris et le clavier sont des capteurs puisqu'on envoie des informations vers le système informatique.

L'écran est un actionneur : le système informatique parvient bien à modifier l'apparence de l'écran physique.

On notera qu'un écran TACTILE est à la fois un capteur et un actionneur.

A quoi peuvent servir les variables globales dans le cadre d'une application graphique ? A imposer une charte graphique commune à plusieurs éléments puisqu'on peut lire les variables globales depuis l'intérieur des fonctions.

Voici un exemple de programme d'interface graphique qui :

  • Importe les fonctionnalités du module d'interface graphique tkinter en le renommant tk.
  • 1 2 3
    # 1 - Importations import tkinter as tk
  • Définit six couleurs via des constantes :
  • 6 7 8 9 10 11 12
    # 2 - Déclaration des constantes COULEUR_0 = "#666666" COULEUR_1 = "#448800" COULEUR_2 = "#884400" COULEUR_3 = "#004488" COULEUR_4 = "#888800" FOND = "black" # Couleur de fond
  • Crée l'interface graphique et stocke sa référence dans une variable nommée application. Elle apparaît en or foncé sur le site pour montrer qu'il s'agit d'une variable liée à l'interface graphique.
  • 27 28 29 30 31 32 33 34
    # 4 - Programme # 4-1 - Création et configuration de la fenêtre du logiciel application = tk.Tk() application.geometry("600x400") application.title("Démonstration lecture des variables globales") application.configure(bg=FOND)
  • Crée et positionne avec place() neufs widgets de type Label-text. wL1C1 veut dire que ce widget doit être sur la première ligne (L1) de la première Colonne (C1).
  • 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
    # 4-2 - Création et affichage des Labels wL1C1 = tk.Label(application, text="L1C1", fg="white", bg=COULEUR_0, width=10, height=5) wL1C1.place(x=25, y=25) wL1C2 = tk.Label(application, text="L1C1", fg="white", bg=COULEUR_0, width=10, height=5) wL1C2.place(x=125, y=25) wL1C3 = tk.Label(application, text="L1C2", fg="white", bg=COULEUR_0, width=10, height=5) wL1C3.place(x=225, y=25) wL2C1 = tk.Label(application, text="L2C3", fg="white", bg=COULEUR_0, width=10, height=5) wL2C1.place(x=25, y=125) wL2C2 = tk.Label(application, text="L2C2", fg="white", bg=COULEUR_0, width=10, height=5) wL2C2.place(x=125, y=125) wL2C3 = tk.Label(application, text="L2C3", fg="white", bg=COULEUR_0, width=10, height=5) wL2C3.place(x=225, y=125) wL3C1 = tk.Label(application, text="L3C1", fg="white", bg=COULEUR_0, width=10, height=5) wL3C1.place(x=25, y=225) wL3C2 = tk.Label(application, text="L3C2", fg="white", bg=COULEUR_0, width=10, height=5) wL3C2.place(x=125, y=225) wL3C3 = tk.Label(application, text="L3C3", fg="white", bg=COULEUR_0, width=10, height=5) wL3C3.place(x=225, y=225)
  • Stocke en ligne 65 dans le tableau tableau_widgets toutes les références des widgets
  • 65
    tableau_widgets = [wL1C1, wL1C2, wL1C3, wL2C1, wL2C2, wL2C3, wL3C1, wL3C2, wL3C3]
  • Indique à l'aide de la méthode bind() de surveiller les événements "Clic avec le bouton gauche" (clic sur le bouton 1) sur les différents widgets : lors d'un cloc, il faudra lancer la fonction événementielle modifier().
  • 67 68 69 70 71 72 73 74 75 76 77
    # 4-3 - Création du gestionnaire d’événements wL1C1.bind('<Button-1>', modifier) # Déclaration manuelle des événéments, c'est long... wL1C2.bind('<Button-1>', modifier) wL1C3.bind('<Button-1>', modifier) wL2C1.bind('<Button-1>', modifier) wL2C2.bind('<Button-1>', modifier) wL2C3.bind('<Button-1>', modifier) wL3C1.bind('<Button-1>', modifier) wL3C2.bind('<Button-1>', modifier) wL3C3.bind('<Button-1>', modifier)

    Notez bien qu'on ne transmet que le nom modifier de la fonction modifier(). Pas de parenthèse. L'explication est dans la partie suivante.

  • Lance l'application en fonctionnement événementiel : à partir de cette ligne, le programme ne fait que surveiller les événements et réagir en conséquence. On sort du mode programmation séquentielle pour rentrer en programmation événementielle en boucle infinie.
  • 79 80
    # 4-4 - Surveillance des événements application.mainloop()

Et on aura alors ceci :

02° Mettre le programme fourni ci-dessous en mémoire et lancer. Cliquer sur les widgets pour voir le résultat.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
# 1 - Importations import tkinter as tk # 2 - Déclaration des constantes COULEUR_0 = "#666666" COULEUR_1 = "#448800" COULEUR_2 = "#884400" COULEUR_3 = "#004488" COULEUR_4 = "#888800" FOND = "black" # Couleur de fond # 3 - Déclaration des fonctions def modifier(event): """Fonction événementielle : event se remplit automatiquement""" widget_clic = event.widget # On récupère le widget ayant créé l'événement couleur_actuelle = widget_clic.cget('bg') # méthode cget permet de lire un attribut d'un widget if couleur_actuelle == COULEUR_0: widget_clic.configure(bg=COULEUR_1) # méthode configure permet de modifier un attribut elif couleur_actuelle == COULEUR_1: widget_clic.configure(bg=COULEUR_2) # 4 - Programme # 4-1 - Création et configuration de la fenêtre du logiciel application = tk.Tk() application.geometry("600x400") application.title("Démonstration lecture des variables globales") application.configure(bg=FOND) # 4-2 - Création et affichage des Labels wL1C1 = tk.Label(application, text="L1C1", fg="white", bg=COULEUR_0, width=10, height=5) wL1C1.place(x=25, y=25) wL1C2 = tk.Label(application, text="L1C1", fg="white", bg=COULEUR_0, width=10, height=5) wL1C2.place(x=125, y=25) wL1C3 = tk.Label(application, text="L1C2", fg="white", bg=COULEUR_0, width=10, height=5) wL1C3.place(x=225, y=25) wL2C1 = tk.Label(application, text="L2C3", fg="white", bg=COULEUR_0, width=10, height=5) wL2C1.place(x=25, y=125) wL2C2 = tk.Label(application, text="L2C2", fg="white", bg=COULEUR_0, width=10, height=5) wL2C2.place(x=125, y=125) wL2C3 = tk.Label(application, text="L2C3", fg="white", bg=COULEUR_0, width=10, height=5) wL2C3.place(x=225, y=125) wL3C1 = tk.Label(application, text="L3C1", fg="white", bg=COULEUR_0, width=10, height=5) wL3C1.place(x=25, y=225) wL3C2 = tk.Label(application, text="L3C2", fg="white", bg=COULEUR_0, width=10, height=5) wL3C2.place(x=125, y=225) wL3C3 = tk.Label(application, text="L3C3", fg="white", bg=COULEUR_0, width=10, height=5) wL3C3.place(x=225, y=225) tableau_widgets = [wL1C1, wL1C2, wL1C3, wL2C1, wL2C2, wL2C3, wL3C1, wL3C2, wL3C3] # 4-3 - Création du gestionnaire d’événements wL1C1.bind('<Button-1>', modifier) # Déclaration manuelle des événéments, c'est long... wL1C2.bind('<Button-1>', modifier) wL1C3.bind('<Button-1>', modifier) wL2C1.bind('<Button-1>', modifier) wL2C2.bind('<Button-1>', modifier) wL2C3.bind('<Button-1>', modifier) wL3C1.bind('<Button-1>', modifier) wL3C2.bind('<Button-1>', modifier) wL3C3.bind('<Button-1>', modifier) # 4-4 - Surveillance des événements application.mainloop()

Questions :

  1. En cliquant sur les carrés, parvient-on bien à modifier leurs couleurs ?
  2. Le seul paramètre de la fonction événementielle modifier() correspond-t-il aux constantes de couleurs ?
  3. La fonction événementielle modifier() parvient-elle à lire les variables globales du programme principal ?

...CORRECTION...

On parvient bien à modifier les couleurs des carrés et pourtant on ne transmet pas les constantes via les paramètres.

La fonction événementielle modifier() ne possède qu'un paramètre nommé event (voir ligne 17).

17
def modifier(event):

On peut en déduire que depuis une fonction, on peut effectivement lire le contenu des variables globales.

La partie suivante vous propose de découvrir ce qui différencie fonction et fonction événementielle.

2 - Evénement Click

03° Nous avons vu que

  • la méthode pour placer les widgets se nomme place(),
  • la méthode pour configurer/modifier l'un des attributs d'un widget se nomme configure(),
  • la méthode pour lire l'un des attributs d'un widget se nomme cget(),

Question : comment se nomme la méthode qui permet de générer une liaison entre un événement et le déclenchement d'une fonction ?

...CORRECTION...

Il s'agit de la méthode bind() qui veut dire lier en anglais.

On notera deux choses importantes :

  1. Lors de la création de l'événement, on ne donne que le nom d'une fonction (modifier ici donc), sans pouvoir lui transmettre d'arguments.
  2. 2
    wL1C1.bind('<Button-1>', modifier)
  3. Cette fonction modifier() n'est néanmoins pas une fonction normale : il s'agit d'une fonction événementielle, elle doit avoir un paramètre qui sera rempli automatiquement par l'application graphique tkinter avec les informations enregistrées lors de la détection de l'événement (position de la souris, la référence du widget on vient de cliquer...) C'est un peu bizarre : on va devoir déclarer un paramètre (souvent nommé event ou juste e) qui sera transmis automatiquement à Python par l'interface Tkinter.

04° Etudier la fonction modifier() proposée. Répondre ensuite aux questions.

15 16 17 18 19 20 21 22 23 24
# 3 - Déclaration des fonctions def modifier(event): """Fonction événementielle : event se remplit automatiquement""" widget_clic = event.widget # On récupère le widget ayant créé l'événement couleur_actuelle = widget_clic.cget('bg') # méthode cget permet de lire un attribut d'un widget if couleur_actuelle == COULEUR_0: widget_clic.configure(bg=COULEUR_1) # méthode configure permet de modifier un attribut elif couleur_actuelle == COULEUR_1: widget_clic.configure(bg=COULEUR_2)
  1. L17 : Comment se nomme le paramètre recevant les informations de l'événement dans cette fonction ?
  2. L19 : Que doit-on taper pour récupérer le widget qui est à l'origine de l'événement ?
  3. L20 : La méthode cget() permet de récupérer l'un des attributs d'un widget. Ici, son fond coloré. Que contient initialement l'attribut bg du widget cliqué (pensez à aller voir la création des widgets sur les lignes 36+) ?
  4. L22 : Que réalise cette instruction ?
  5. Dans quel cas va-t-on réaliser la ligne 24 ?

...CORRECTION...

  1. Comment se nomme le paramètre recevant les informations de l'événement dans cette fonction ?
  2. Le paramètre se nomme event.

  3. Que doit-on taper pour récupérer le widget qui est à l'origine de l'événement ?
  4. Il faut taper event.widget

  5. La méthode cget() permet de récupérer l'un des attributs d'un widget. Ici, son fond coloré. Que contient initialement l'attribut bg du widget cliqué ?
  6. Initialement, le fond coloré avait été réglé avec COULEUR_0.

  7. Que réaliser alors la ligne 22 ?
  8. 22
    widget_clic.configure(bg=COULEUR_1) # méthode configure permet de modifier un attribut

    En Français, cela veut dire d'activer la méthode configure() sur le widget dont on a stocké la référence dans widget_clic et de changer son attribut fond coloré : on y place la couleur COULEUR_1.

  9. Dans quel cas va-t-on réaliser la ligne 24 ?
  10. Cette fois, on active la méthode configure() sur le widget dont on a stocké la référence dans widget_clic et on change son attribut fond coloré : on y place la couleur suivante COULEUR_2.

✎ 05 - Faire vérifier° Compléter la fonction modifier() pour pouvoir avoir un cycle de couleur 0 vers 1, 1 vers 2, 2 vers 3, 3 vers 4 et 4 vers 1 lorsqu'on clique sur les widgets.

Il reste bien des choses à dire sur la gestion des événements. Mais le but ici était simplement de vous montrer qu'on pouvait lire les variables globales depuis une fonction.

3 - Conclusion : lire le tableau

Imaginons qu'on veuille modifier la couleur de tous les carrés lorsqu'on clique sur l'un d'entre eux avec un clic-droit.

Nous avions enregistré le tableau des 9 widgets, vous vous souvenez ?

65
indice 0 1 2 3 4 5 6 7 8 9 tableau_widgets = [wL1C1, wL1C2, wL1C3, wL2C1, wL2C2, wL2C3, wL3C1, wL3C2, wL3C3]

Cela veut dire qu'avec :

  • tableau_widgets[0] on récupére la référence du widget wL1C1.
  • tableau_widgets[8] on récupére la référence du widget wL3C3.
  • tableau_widgets[9] on déclenche une erreur puisque l'indice 9 n'existe pas dans un tableau de 9 éléments. Les indices vont de 0 à 8 uniquement.

Comme tableau_widgets est une variable globale, nous allons pouvoir la lire depuis la fonction et déplacer un à un tous les carrés à l'aide de leurs références qui se trouvent dans ce tableau global.

06° Exécuter ce programme : avec un clic-droit sur les carrés, on parvient à les déplacer vers la droite.

Lire les modifications surlignées puis répondre à ces questions :

  1. Comment parvient-on à créer les surveillances des clics-droits en deux lignes uniquement ?
  2. Qu'aurions-nous dû taper si on n'avait pas utilisé de boucle ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
# 1 - Importations import tkinter as tk # 2 - Déclaration des constantes COULEUR_0 = "#666666" COULEUR_1 = "#448800" COULEUR_2 = "#884400" COULEUR_3 = "#004488" COULEUR_4 = "#888800" FOND = "black" # Couleur de fond # 3 - Déclaration des fonctions def modifier(event): """Fonction événementielle : event se remplit automatiquement""" widget_clic = event.widget # On récupère le widget ayant créé l'événement couleur_actuelle = widget_clic.cget('bg') # méthode cget permet de lire un attribut d'un widget if couleur_actuelle == COULEUR_0: widget_clic.configure(bg=COULEUR_1) # méthode configure permet de modifier un attribut elif couleur_actuelle == COULEUR_1: widget_clic.configure(bg=COULEUR_2) def deplacer(event): """Fonction événementielle : event se remplit automatiquement""" for i in range( len(tableau_widgets) ): widget_en_cours = tableau_widgets[i] cx = widget_en_cours.winfo_x() # Renvoie la coordonnée x du widget cy = widget_en_cours.winfo_y() # Renvoie la coordonnée y du widget widget_en_cours.place(x=cx+10, y=cy) # 4 - Programme # 4-1 - Création et configuration de la fenêtre du logiciel application = tk.Tk() application.geometry("600x400") application.title("Démonstration lecture des variables globales") application.configure(bg=FOND) # 4-2 - Création et affichage des Labels wL1C1 = tk.Label(application, text="L1C1", fg="white", bg=COULEUR_0, width=10, height=5) wL1C1.place(x=25, y=25) wL1C2 = tk.Label(application, text="L1C1", fg="white", bg=COULEUR_0, width=10, height=5) wL1C2.place(x=125, y=25) wL1C3 = tk.Label(application, text="L1C2", fg="white", bg=COULEUR_0, width=10, height=5) wL1C3.place(x=225, y=25) wL2C1 = tk.Label(application, text="L2C3", fg="white", bg=COULEUR_0, width=10, height=5) wL2C1.place(x=25, y=125) wL2C2 = tk.Label(application, text="L2C2", fg="white", bg=COULEUR_0, width=10, height=5) wL2C2.place(x=125, y=125) wL2C3 = tk.Label(application, text="L2C3", fg="white", bg=COULEUR_0, width=10, height=5) wL2C3.place(x=225, y=125) wL3C1 = tk.Label(application, text="L3C1", fg="white", bg=COULEUR_0, width=10, height=5) wL3C1.place(x=25, y=225) wL3C2 = tk.Label(application, text="L3C2", fg="white", bg=COULEUR_0, width=10, height=5) wL3C2.place(x=125, y=225) wL3C3 = tk.Label(application, text="L3C3", fg="white", bg=COULEUR_0, width=10, height=5) wL3C3.place(x=225, y=225) tableau_widgets = [wL1C1, wL1C2, wL1C3, wL2C1, wL2C2, wL2C3, wL3C1, wL3C2, wL3C3] # 4-3 - Création du gestionnaire d’événements for i in range( len(tableau_widgets) ): # Déclaration automatique, c'est plus joli non ? tableau_widgets[i].bind('<Button-3>', deplacer) wL1C1.bind('<Button-1>', modifier) # Déclaration manuelle des événéments, c'est long... wL1C2.bind('<Button-1>', modifier) wL1C3.bind('<Button-1>', modifier) wL2C1.bind('<Button-1>', modifier) wL2C2.bind('<Button-1>', modifier) wL2C3.bind('<Button-1>', modifier) wL3C1.bind('<Button-1>', modifier) wL3C2.bind('<Button-1>', modifier) wL3C3.bind('<Button-1>', modifier) # 4-4 - Surveillance des événements application.mainloop()

...CORRECTION...

On utilise une boucle POUR avec une variable de boucle i qui va prendre successivement les valeurs 0, 1, 2, 3... jusqu'à 8. Pourquoi ? Simplement car la longueur du tableau est de 9.

Nous aurions pu taper ceci si nous avions voulu nous passer de la boucle :

1 2 3 4 5 6 7 8 9
wL1C1.bind('<Button-3>', deplacer) # Déclaration manuelle des événéments, c'est long... wL1C2.bind('<Button-3>', deplacer) wL1C3.bind('<Button-3>', deplacer) wL2C1.bind('<Button-3>', deplacer) wL2C2.bind('<Button-3>', deplacer) wL2C3.bind('<Button-3>', deplacer) wL3C1.bind('<Button-3>', deplacer) wL3C2.bind('<Button-3>', deplacer) wL3C3.bind('<Button-3>', deplacer)

07° Regardons comment fonctionne la fonction événementielle deplacer().

  1. Cette fonction reçoit-elle le tableau via son paramètre ou parvient-elle à le lire car le tableau est une variable globale  ?
  2. Dans le cas de notre programme, quelles vont être les valeurs successives prises par la variable de boucle i ?
  3. Que contient widget_en_cours lors du premier tour de boucle ?
  4. Comment se nomme la méthode permettant de récupérer la coordonnée x où est placé un widget ?
  5. Pourquoi le widget se déplace-t-il à droite ?
26 27 28 29 30 31 32
def deplacer(event): """Fonction événementielle : event se remplit automatiquement""" for i in range( len(tableau_widgets) ): widget_en_cours = tableau_widgets[i] cx = widget_en_cours.winfo_x() # Renvoie la coordonnée x du widget cy = widget_en_cours.winfo_y() # Renvoie la coordonnée y du widget widget_en_cours.place(x=cx+10, y=cy)

...CORRECTION...

  1. Cette fonction reçoit-elle le tableau via son paramètre ou parvient-elle à le lire car le tableau est une variable globale  ?
  2. Elle ne reçoit pas cette variable. Mais, la fonction peut la lire puisque le tableau est une variable globale.

  3. Dans le cas de notre programme, quelles vont être les valeurs successives prises par la variable de boucle i ?
  4. Le tableau contient 9 widgets dont les indices vont de 0 à 8.

  5. Que contient widget_en_cours lors du premier tour de boucle ?
  6. L'indice vaut 0 au départ. Le widget est donc celui stocké à l'indice 0. C'est celui qui correspond à wL1C1

  7. Comment se nomme la méthode permettant de récupérer la coordonnée x où est placé un widget ?
  8. Ligne 30. On voit qu'il faut utiliser winfo_x().

  9. Pourquoi le widget se déplace-t-il à droite ?
  10. Ligne 32. On voit qu'on place widget en rajoutant 10 à la coordonnée qu'on a lu avec winfo_x().

CONCLUSION

Vous connaissez maintenant la notion de variables globales dont la portée en lecture s'étend jusqu'aux fonctions.

Leur utilisation peut paraître sympathique mais les variables globales ne devront être utilisées.

Pourquoi ? Nous verrons que leur utilisation rend la correction et la vérification des fonctions bien délicates.

Dans quel cas les utiliser alors ? Dans le cadre de NSI, on peut se limiter à ces deux cas :

  1. Pour permettre aux fonctions événementielles d'avoir accès à des informations non liées au widget ayant déclenché l'événement (comme ici)
  2. Pour éviter de créer des fonctions dont la plupart des paramètres recoivent des CONSTANTES globales (comme dans votre projet console qcm, jeu ou générateur de scénario)

4 - FAQ

Et si on veut faire plus de choses avec Tkinter ?

Il existe beaucoup de documentation sur le Web.

Les informations risquent néanmoins d'être encore difficiles à comprendre pour le moment.

Sinon, vous trouverez ci-dessous un petit tuto pour faire quelques petites manipulations :

FICHE Tkinter

J'ai vu des programmes avec un mot-clé global. C'est quoi ?

C'est un moyen permettant à une fonction de parvenir à agir sur une variable globale, une variable définie dans le corps du programme.

Il ne faut pas l'utiliser dans le cadre d'un programme, à moins d'y être contraint.

Si vraiment vous voulez savoir comment ça fonctionne, vous pouvez lire la suite. Mais bon : vous n'aurez pas le droit de l'utiliser en NSI de toutes manières. C'est juste de la curiosité.

...CORRECTION...

Cette partie comporte des informations qui ne sont pas au programme de NSI. On va vous montrer une fois qu'on peut modifier les variables globales depuis une fonction. Ensuite, il ne faudra plus le faire. Cela pose des problèmes de stabilité et de solidité des applications réalisées.

Par contre, on trouve sur le Web de nombreux codes qui l'utilise. Bref, autant savoir que ça existe, même si son utilisation n'est pas autorisée ou conseillée.

Comment faire alors pour modifier une variable globale depuis une fonction ?

Voyons comment faire avec ce petit bout de cours fortement optionnel :

Rappel : comportement de Python par défaut
  • une fonction peut lire une variable globale.
  • une fonction ne peut pas modifier une variable globale
    • l'utilisation d'une affectation (=) crée simplement une variable locale portant le même nom.
Nouveau : modification du comportement par défaut
  • une fonction peut modifier une variable globale si on lui en donne l'autorisation :
    • en utilisant le mot-clé global suivi du nom de la variable avant de l'affecter

Mise en pratique immédiate :

1 2 3 4 5 6 7 8 9
ennemi = "Darth Vador"
def test(): global ennemi ennemi = "Palpatine"
print(ennemi) test() print(ennemi)

Ligne 7 : On affiche le contenu "Darth Vador"

Lignes 8 puis 4 et 5 : On permet à la fonction de modifier la variable en "Palpatine"

Ligne 9 : La variable globale contient bien "Palpatine" maintenant.

20° Lancer ce programme sur Python Tutor ou Thonny en mode DEBUG pour visualiser la modification du contenu de la variable.

21° Utiliser maintenant Thonny en mode DEBUG avec visualisation du tas (heap) pour connaitre le contenu ET l'id de la variable au cours de l'execution du programme. L'id de la variable globale a-t-elle été modifié après la ligne 5 ? Pour vous convaincre de la différence sans la ligne 4, vous pouvez la supprimer et relancer un nouveau debug.

CLIQUEZ ICI POUR VOIR LE CONTENU DES VARIABLES :

test :

ennemi :


Id 0x6E18 :

Id 0x3FC0 :

Id 0xB030 :

1 2 3 4 5 6 7 8 9
ennemi = "Darth Vador"
def test(): global ennemi ennemi = "Palpatine"
print(ennemi) test() print(ennemi)

Voilà, nous sommes parvenus à modifier une variable globale depuis une fonction. Attention, n'oubliez pas que la variable change d'identifiant associé, comme à chaque fois qu'on utilise une affectation  = .

Spécificités des portées en fonction des variables

La portée des variables globales et locales, ainsi que la façon dont on peut les modifier est variable en fonction du langage de programmation. Il s'agit d'une des premières choses qu'il faut regarder et comprendre lorsqu'on s'attaque à un nouveau langage. Pour vous, c'est fait avec Python maintenant.

Note finale : Limitez l'utilisation des variables globales !

La modification des variables globales avec global doit rester marginale dans vos programmes. Il est en effet difficile de maintenir fonctionnel un code qui comporte plusieurs variables modifiées par plusieurs fonctions créées par des personnes différentes.

Si vous devez utilisez des variables globales (même en lecture simple), respectez au moins ces trois points :

  1. Placer les clairement en début de code dans la partie adéquate de façon à clairement les mettre en évidence.
  2. Placer des commentaires pour expliquer à quoi elles servent
  3. Donner leur des noms suffisamment rares pour que quelqu'un ne les écrase dans une fonction par une variable locale portant le même nom : si l'une de vos variables globales se nomme x, il ne faudra pas vous plaindre si l'une des personnes de votre équipe utilise aussi ce nom dans l'une de ses fonctions !

Sachez que nous verrons plus tard des outils nous permettant de nous passer des modifications de variables globales depuis les fonctions. Vous pouvez donc les utiliser pour l'instant, mais gardez à l'esprit qu'il s'agit plutôt d'une mauvaise pratique.

On retiendra donc qu'une variable globale est une variable déclarée dans le corps du programme lui-même.

Une telle variable peut être lue mais pas modifiée depuis une fonction.

Activité publiée le 01 11 2020
Dernière modification : 30 01 2022
Auteur : ows. h.