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 :

fonction "lambda" dans commande bouton


Sujet :

Tkinter Python

  1. #1
    Membre à l'essai
    Homme Profil pro
    Agriculteur
    Inscrit en
    Juillet 2012
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Agriculteur
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Juillet 2012
    Messages : 39
    Points : 22
    Points
    22
    Par défaut fonction "lambda" dans commande bouton
    Bonjour,

    Je cherche à réaliser une petite interface pour commander des moteurs (appellés vis) pour doser l'aliment de mes animaux.
    En tant que débutant, j'ai ébauché un code à l'aide d'un autre forumhttp://www.developpez.net/forums/d12...n-incliquable/

    Mais je ne comprends pas l'intérêt de poser une fonction "lambda" dans l'instruction"command" de mes boutons.
    Je pensais que l'instruction "command=fx" dans un bouton Tk lançait la fonction Tk mais apparemment j'ai manqué un épisode. Quelqu'un peut-il m'éclaircir sur ce point ??

  2. #2
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonjour,

    Voila bien quelque chose qui se doit être acquis, surtout avec tkinter.

    Dans un premier temps des généralités sur les fonctions:
    Une fonction est définie comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    def nomdelafonction(paramètres):
        <bloc d'instructions de la fonction>
    Une fonction est évaluée par l'interpréteur lorsque sont nom est suivit de ()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> def foo():
    ...     print('in foo')
    ... 
    >>> foo()
    in foo
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> def foo(p):
    ...     print(p)
    ... 
    >>> foo('in foo')
    in foo
    Une fonction qui ne 'retourne' (return) rien retourne None
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    >>> def foo():
    ...     pass
    ... 
    >>> foo()
    >>> f = foo()
    >>> f
    >>> f == None
    True
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> def foo(p):
    ...     return p
    ... 
    >>> f = foo('bar')
    >>> f
    'bar'
    Revenons à notre command= du Widget Button
    Lorsque nous écrivons command=foo on donne en référence le nom de la fonction foo à tkinter qui le stocke dans le command du Button (c'est plus compliqué mais je vais rester dans du général). La fonction seras évaluée (foo()) lors du relâchement du bouton gauche de la souris après avoir cliquer sur le Button.

    Cela c'est pour tkinter mais sortons du contexte car la question est plus générale.

    Pour ne pas nous emmêler les pinceaux changeons de nom et utilisons 'f' a la place de 'command'.
    Commençons par ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> def foo(p):
    ...     print(p)
    ... 
    >>> f = foo
    >>> f
    <function foo at 0xb732c22c>
    Ici f fait référence à la fonction foo. foo accepte un argument que j'ai nommer p.
    Si j'écris
    On vois bien (print(p)) que l'interpréteur évalue directement foo(1).
    Comme notre fonction ne retourne rien f = None
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> def foo(p):
    ...     print(p)
    ... 
    >>> f = foo
    >>> f
    <function foo at 0xb732c22c>
    >>> f = foo(1)
    1
    >>> f == None
    True
    Ce n'est pas ce que l'on souhaite et pour arriver à nos fin on utilise donc lambda:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> f = lambda: foo(1)
    >>> f
    <function <lambda> at 0xb732c2ac>
    >>> f()
    1
    Ici ce n'est pas foo(1) qui est 'stocker' dans f mais la fonction lambda.

    Compliquons la chose:

    Dans un premier temps une généralité sur range puisque utilisé dans le code qui suit
    This is a versatile function to create lists containing arithmetic progressions. It is most often used in for loops. The arguments must be plain integers. If the step argument is omitted, it defaults to 1. If the start argument is omitted, it defaults to 0. The full form returns a list of plain integers [start, start + step, start + 2 * step, ...]. If step is positive, the last element is the largest start + i * step less than stop; if step is negative, the last element is the smallest start + i * step greater than stop. step must not be zero (or else ValueError is raised).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    >>> range(3)
    range(0, 3)
    >>> for i in range(3):
    ...     print(i)
    ... 
    0
    1
    2
    Revenons à lambda:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> l = []
    >>> for i in range(3):
    ...     l.append(lambda: foo(i))
    ... 
    >>> l
    [<function <lambda> at 0xb732c2ec>, <function <lambda> at 0xb732c42c>, <function <lambda> at 0xb732c46c>]
    Nous avons ici une liste l qui contiens trois références à des fonction lambda. Nous pouvons retrouver ses fonctions via l'index de l. l[0] étant la première 'valeur' (fonction) et l[2] la dernière.
    On remarque que c'est une nouvelle fonction à chaque fois
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [<function <lambda> at 0xb732c2ec>, <function <lambda> at 0xb732c42c>, <function <lambda> at 0xb732c46c>]
    Testons cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> l[0]()
    2
    >>> l[1]()
    2
    >>> l[2]()
    2
    Ballot ça...
    Que ce passe t'il ? Nous stockons une fonction lambda avec pour argument i. Hors lorsque nous évaluons la fonction le code a fini sa 'boucle' for et la valeur de i est la dernière valeur donnée par range, soit 2.
    Ce n'est toujours pas ce que nous cherchons...

    Pour que la fonction lambda contienne la bonne valeur nous devons lui donner au moment de la création. La fonction lambda étant construite comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    lambda paramètres: <bloc de code>
    Nous pourrions utiliser:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    >>> l = []
    >>> for i in range(3):
    ...     l.append(lambda i: foo(i))
    mais en fait non:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> l[0]
    <function <lambda> at 0xb732c32c>
    >>> l[0]()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: <lambda>() takes exactly 1 argument (0 given)
    Ici lambda attend un argument...
    Toujours pas ce que nous cherchons...

    En fait nous cherchons à passer i au moment de la création.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    >>> l = []
    >>> for i in range(3):
    ...     l.append(lambda ind=i: foo(ind))
    ... 
    >>> l[0]
    <function <lambda> at 0xb732c3ac>
    >>> l[0]()
    0
    >>> l[1]()
    1
    >>> l[2]()
    2
    Comprenez vous ?

    @+
    Merci d'utiliser le forum pour les questions techniques.

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    PauseKawa a d'autres vues sur ces choses.
    Plusieurs perspectives peuvent aider.

    Citation Envoyé par Farmer64 Voir le message
    Je pensais que l'instruction "command=fx" dans un bouton Tk lançait la fonction Tk mais apparemment j'ai manqué un épisode. Quelqu'un peut-il m'éclaircir sur ce point ??
    Techniquement, command=function ne lance pas la fonction mais indique l'action (fonction) qui devra être lancée lorsqu'on appuiera sur le Button.

    Mais je ne comprends pas l'intérêt de poser une fonction "lambda" dans l'instruction"command" de mes boutons.
    L'intérêt de lambda est de permettre de construire des "fonctions" à la volée en une seule ligne. L'intérêt de passer des fonctions en paramètre ou de construire des fonctions "à la volée" n'est pas évident pour les débutants.

    Lorsque vous aurez acquis suffisamment d'assurance pour vous lancer dans des projets "plus touffu", vous vous poserez des questions sur comment organiser tout çà et à ce moment là, classes, modules, fonction en paramètre,... apporteront des pistes pour les réponses.

    En attendant, essayez de jouer et réfléchir sur le code ci dessous:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def adder(a):
        def inner(b):
            return a + b
        return inner
    fx = adder(2)
    fy = adder(4)
    print (fx(3), fy(3))
     
    def adder(a, b):
        return a + b
    fx = lambda y: adder(2, y)
    fy = lambda y: adder(4, y)
    print (fx(3), fy(3))
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    Par défaut
    Merci pour l'intervention wiztricks

    C'est vrais que l'approche proposée est complètement orientée tkinter* où lambda est utilisé, principalement, pour éviter les répétitions inutiles de fonctions (et ce pour command, after, bind etc...).
    Exemple:
    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    from tkinter import *
     
     
    def Affiche(e):
        lab.config(text=e.get())
     
    def UseLab1():
        Affiche(entry1)
     
    def UseLab2():
        Affiche(entry2)
     
    def UseLab3():
        Affiche(entry3)
     
     
    fen1 = Tk()
    lab = Label(fen1, text="ZERO", padx=3, pady=2)
    lab.grid(row=0, column=1, columnspan=2)
    entry1 = Entry(fen1)
    entry1.grid(row=1, column=1, padx=3, pady=2)
    entry1.insert(0, "UN")
    entry2 = Entry(fen1)
    entry2.grid(row=2, column=1, padx=3, pady=2)
    entry2.insert(0, "DEUX")
    entry3 = Entry(fen1)
    entry3.grid(row=3, column=1, padx=3, pady=2)
    entry3.insert(0, "TROIS")
    Button(fen1, text="Use 1", command=UseLab1).grid(row=1, column=2, padx=3, pady=2)
    Button(fen1, text="Use 2", command=UseLab2).grid(row=2, column=2, padx=3, pady=2)
    Button(fen1, text="Use 3", command=UseLab3).grid(row=3, column=2, padx=3, pady=2)
    Button(fen1, text="Quitter", command=fen1.destroy).grid(row=4, column=1, columnspan=2, padx=3, pady=2)
    fen1.mainloop()
    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    from tkinter import *
     
     
    def Affiche(e):
        lab.config(text=e.get())
     
     
    fen1 = Tk()
    lab = Label(fen1, text="ZERO", padx=3, pady=2)
    lab.grid(row=0, column=1, columnspan=2)
    entry1 = Entry(fen1)
    entry1.grid(row=1, column=1, padx=3, pady=2)
    entry1.insert(0, "UN")
    entry2 = Entry(fen1)
    entry2.grid(row=2, column=1, padx=3, pady=2)
    entry2.insert(0, "DEUX")
    entry3 = Entry(fen1)
    entry3.grid(row=3, column=1, padx=3, pady=2)
    entry3.insert(0, "TROIS")
    Button(fen1, text="Use 1", command=lambda : Affiche(entry1)).grid(row=1, column=2, padx=3, pady=2)
    Button(fen1, text="Use 2", command=lambda : Affiche(entry2)).grid(row=2, column=2, padx=3, pady=2)
    Button(fen1, text="Use 3", command=lambda : Affiche(entry3)).grid(row=3, column=2, padx=3, pady=2)
    Button(fen1, text="Quitter", command=fen1.destroy).grid(row=4, column=1, columnspan=2, padx=3, pady=2)
    fen1.mainloop()
    Mais en fait que cela soit lambda : Affiche(entry1) ou fx = lambda y: adder(2, y) le besoin est le même. Remplacer par une ligne une petite fonction 'inutile'.
    Je ne fais que rajouter une approche sur le moment ou la fonction est évaluée et ce qu'il en est des arguments à ce moment là.
    Les vues sont elles si différentes ?

    @+

    *C'est volontaire vu la question. J'ai toutefois essayer de sortir du contexte tkinter pour montrer que cela est plus général.
    Merci d'utiliser le forum pour les questions techniques.

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut PauseKawa,
    Citation Envoyé par PauseKawa
    Les vues sont elles si différentes ?
    Mais il fallait quand justifier un peu le "pourquoi en rajouter"!

    Ce qui m'a gratté, c'est la candeur de la question et le "compliqué"/"long" de la réponse.

    En jouant avec tkinter, le PO n'a pas choisi le chemin le plus facile pour "apprendre" la programmation. Un GUI, c'est compliqué. Il faut avoir un peu de bouteille, côté programmation, pour comprendre des tas de concepts à mettre en œuvre pour être à l'aise côté GUI.

    L'appropriation des concepts de base passe par une construction personnelle de leur représentation que l'on affine dans le temps. On peut écouter ou lire n'importe quelle histoire: il faut avoir mis les mains dans le cambouis pour que çà rentre.

    D'où une reprise des questions "essentielles" et des réponses "rapides" avec du "food to thinks" à la fin.
    Cela me semblait nécessaire vu le "compliqué"/"long" de la réponse que vous avez faite. J'espère que ce sera "utile" pour le PO et d'autres lecteurs.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonsoir,

    Citation Envoyé par wiztricks Voir le message
    Ce qui m'a gratté, c'est la candeur de la question et le "compliqué"/"long" de la réponse.
    J'en suis bien conscient.
    A la lecture des questions posées sur le forum par Farmer64 il m'as sembler utile de bien préciser chaque étape de l’explication tout en lui montrant Python sous la 'couche' tkinter.
    Pour ce qui est du "compliqué" j'ai fais au mieux: Difficile de revenir en arrière, même en connaissance du sujet. A voir le sentiment de Farmer64 et des lecteurs.

    @+

    Note: Ceci dit le food to thinks est sans doute plus lourd a digérer pour les neurones d'un débutant que ma longue explication... Non ?
    Merci d'utiliser le forum pour les questions techniques.

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Citation Envoyé par PauseKawa Voir le message
    Note: Ceci dit le food to thinks est sans doute plus lourd a digérer pour les neurones d'un débutant que ma longue explication... Non ?
    Expliquer ou proposer des constructions qui donnent à réfléchir?
    Il n'y a pas de "bonne réponse".
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  8. #8
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Il n'y a pas de "bonne réponse".
    Exact. Pas sans les bases.
    Merci d'utiliser le forum pour les questions techniques.

Discussions similaires

  1. Fonction "get.hist.quote" dans {tseries}..
    Par Jack_dev dans le forum R
    Réponses: 1
    Dernier message: 24/11/2014, 12h57
  2. Passage d'un String PHP dans fonction javascript et quotes
    Par roukgreg dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 14/05/2013, 14h48
  3. [Fonction] Quote et guillemet dans un textarea
    Par ddelec24 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 11/03/2007, 15h51

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