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.