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

  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 : 42

    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 304
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 304
    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 304
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 304
    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

  7. #7
    Expert confirmé

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 304
    Par défaut
    Au temps pour moi, c'est sous python2.x que j'avais une erreur, mais avec python3 le code initial donne bien le résultat attendu.

    vincent

  8. #8
    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,

    Par contre (et bien que cela fonctionne) il me semble que sous Python 3.x (que je n'utilise pas) la fonction lambda dois comporter des parenthèses (vrais/faux ?).
    Dans ce cas doit on écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    command=lambda i=i:(print(i))
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    command=(lambda i=i:print(i))
    ?

    Aucune idée mais à vérifier.

    @+

    Edit pour le smiley

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 99
    Par défaut
    Dans python 3, print est une fonction comme une autre.
    Cela implique que l'on doit mettre l'argument entre parenthèse mais ça veut dire que l'on peut aussi l'utiliser comme n'importe quelle fonction.

    Dans python 2, print est un mot-clé (comme if, while, ...) et doit donc remplir des conditions syntactiques (par exemple, on ne peut pas s'en servir comme argument d'une autre fonction ou dans un lambda), je ne connais pas précisément ces conditions mais grosso modo, on ne peut le mettre qu'en début de ligne

  10. #10
    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,

    Je ne parle pas de print qui est bien une fonction en python 3.x mais de lambda.
    Doit on le mettre entre parenthèse ?

    @+

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 99
    Par défaut
    Oups pardon, j'ai lu un peu trop rapidement.

    Bon après vérification, ça marche dans les deux cas (avec ou sans parenthèse)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    command=lambda i=i:print(i)
    fonctionne aussi.

  12. #12
    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
    Re,

    Autant pour moi, c'est dans les expressions conditionnelles que j'avais vu cela avec lambda.
    Le code présenté est donc bon.

    @+

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