Terminale NSI — Programmation fonctionnelle (hors attendus stricts)
Séance bonus — Tkinter et closures
Statut de cette séance
Hors attendus stricts du chapitre (programmation événementielle), proposée en bonus car elle réinvestit les closures et lambdas de la séance 3.1. Une fenêtre Tkinter minimale
import tkinter as tk
fenetre = tk.Tk()
label = tk.Label(fenetre, text="Bonjour !")
label.pack()
bouton = tk.Button(fenetre, text="Clique-moi", command=dire_bonjour)
fenetre.mainloop()
Piège
command=dire_bonjour() (avec parenthèses) exécute la fonction tout de suite. Il faut passer la fonction sans l'appeler : command=dire_bonjour.2. Exercice 1 — Compteur de clics
Bouton qui incrémente un compteur affiché à chaque clic, via une closure avec nonlocal.
Voir la réponse
def cree_gestionnaire_clics():
compteur = 0
def au_clic():
nonlocal compteur
compteur += 1
label.config(text=f"Clics : {compteur}")
return au_clic
bouton = tk.Button(fenetre, text="Cliquer", command=cree_gestionnaire_clics())
3. Exercice 2 — La symphonie des chiffres
def affiche(n):
label.config(text=f"Bouton {n} cliqué !")
for i in range(5):
bouton = tk.Button(fenetre, text=str(i), command=lambda: affiche(i))
bouton.pack(side="left")
a) Prédis ce qui s'affiche pour chaque bouton. b) Teste. c) Corrige.
Voir la réponse
Tous les boutons affichent « Bouton 4 cliqué ! » — chaque lambda capture la variable i par référence, et à la fin de la boucle i vaut 4 pour toutes.
for i in range(5):
bouton = tk.Button(fenetre, text=str(i), command=lambda i=i: affiche(i))
bouton.pack(side="left")
Le paramètre par défaut i=i force l'évaluation immédiate de i à la création de chaque lambda.
Exercice défi (bonus)
Défi défi
Reproduis le même piège sans Tkinter, avec une liste de fonctions créées en boucle.
Voir la réponse
fonctions = []
for i in range(5):
fonctions.append(lambda: i)
print([f() for f in fonctions]) # [4, 4, 4, 4, 4]
# correction :
fonctions = []
for i in range(5):
fonctions.append(lambda i=i: i)
print([f() for f in fonctions]) # [0, 1, 2, 3, 4]
Le piège n'a rien de spécifique à Tkinter : toute closure créée en boucle est concernée.