IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Tkinter Python Discussion :

For a in b et lambda


Sujet :

Tkinter Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2005
    Messages : 130
    Par défaut For a in b et lambda
    Bonjour,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    from tkinter import *
    liste = [ 'a','b','c']
    root = Tk()
    canvas = Canvas(root)
    canvas.pack()
    for i in liste :
        Button(master = root,text=i, command=lambda:print(i)).pack()
    root.mainloop()
    Dans le code ci dessus il semblerais logique qu'en cliquant sur une lettre, elle se print dans la shell, or c'est systématiquement là dernière ("c" içi) qui s'affiche.

    Je me sert de ce code dans un autre contexte je voudrais savoir si vous aviez un moyen de remédier au problême...

    Merci, j'espère avoir bien expliqué.

  2. #2
    Membre éprouvé
    Inscrit en
    Avril 2010
    Messages
    99
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Avril 2010
    Messages : 99
    Par défaut
    Bonjour,

    Lorsque la fonction lambda:print(i) est appelée (c'est à dire à l'intérieur de la boucle root.mainloop()), la valeur de i est celle que prend i lorsque le programme rentre dans root.mainloop() et non pas celle que prend i lorsque la fonction est déclarée.

    Si tu veux que ton programme marche comme tu le souhaites, tu peux utiliser la fonction functools.partial.

    Ca donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from tkinter import *
    import functools
    
    liste = [ 'a','b','c']
    root = Tk()
    canvas = Canvas(root)
    canvas.pack()
    for i in liste :
        Button(master = root,text=i, command=functools.partial(print, i)).pack()
    root.mainloop()
    J'espère avoir moi aussi était clair.

    Pour plus d'aide sur la fonction partial
    http://docs.python.org/library/functools.html


    ps: Ce code ne marche que pour python 3 (dans python 2, print est un mot-clé et pas une fonction) mais je crois que le code que tu as donné l'était aussi.

  3. #3
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour,

    Dans ce cas il est nécessaire de donner la variable au moment de la création.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    from tkinter import *
    liste = [ 'a','b','c']
    root = Tk()
    canvas = Canvas(root)
    canvas.pack()
    for i in liste:
        Button(master = root,text=i, command=lambda i=i:print(i)).pack()
    root.mainloop()
    @+

  4. #4
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Bonjour,

    Tu instancies trois fois de suite le même objet, seule la troisième instance subsiste, donc i = c.

    Qui plus est, cette instance n'est pas identifiée, comment fais-tu pour utiliser ton bouton dans la suite de ton code, avec le mot Button ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    button_1 = Button(root = ....
    button_2 = Button(root ...
    button_3 = Button(ro ....
    Et je me demande si tu ne dois pas séparer le .pack() qui retourne peut-être None. A vérifier.

    Vincent

  5. #5
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour,

    Ce n'est pas le même objet, un widget différent est créé a chaque fois. La fonction/procédure lambda est stockée dans le command du widget.
    lambda permet de ne pas exécuter une fonction/procédure simple lors de la création.

    Exemple:
    command=sys.exit(0)
    command=lambda:sys.exit(0)

    Dans le cade d'un command=lambda
    Si c'est une procédure tu peut écrire command=lambda:taprocédure
    Ex : command=quit
    Si c'est une fonction avec une variable 'fixe'
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    command=lambda:tafonction(tavariable)
    et cela utiliseras lors de l'exécution tavariable telle qu'elle est définie a la fin de la création (ici a la fin du for et si elle n'est pas modifié lors de l'exécution).
    Si c'est une variable que tu souhaite utiliser tu dois la nommer dans le lambda (voir le code donné i=i).

    i='c' car il est appelé à l'exécution (de l'event) et à l'exécution i='c' car for i in liste est arrivé a la fin de la liste ('c') à la fin de la création des widgets.

    Je ne vois pas l'intérét de nommer un widget si tu n'y fais pas rérérence par la suite.

    Effectivement dans button_1 = Button(root).pack() (grid, place) button_1=None puisque pack() (grid, place) est une procédure est ne retourne (return) rien.

    @+

    Edit : bien différencier création et exécution (ici l'event du widget)

  6. #6
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Oui d'accord, mais je me disais qu'un bouton avait des chance d'être référencé par après.

    Cela dit, j'ai testé le code après mofications (print à la suite de lambda génère une erreur de syntaxe):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    # -*- coding: utf-8 -*-
     
    from Tkinter import *
    liste = [ 'a','b','c']
    root = Tk()
    canvas = Canvas(root)
    canvas.pack()
    for i in liste:
        Button(master=root, text=i, command=lambda a=i: bind(a)).pack()
     
    def bind(var):
        print var
     
    root.mainloop()
    Et le problème cité n'apparaît nullement.

    vincent

Discussions similaires

  1. emacs for ever
    Par spycat dans le forum Autres éditeurs
    Réponses: 4
    Dernier message: 18/09/2003, 11h36
  2. unable to create INITIAL extent for segment in tablespace
    Par Ludolitaliano dans le forum Administration
    Réponses: 4
    Dernier message: 11/09/2003, 16h43
  3. qbasic : pause avec FOR-NEXT
    Par clood200 dans le forum Langages de programmation
    Réponses: 2
    Dernier message: 08/08/2003, 16h51
  4. [Turbo C++] Fonciton containing for are not expanded inline
    Par BuG dans le forum Autres éditeurs
    Réponses: 6
    Dernier message: 17/02/2003, 06h48
  5. [VB6] For Each ... In ...
    Par Troopers dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 03/02/2003, 12h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo