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

Python Discussion :

passage de "self" à une méthode statique ?


Sujet :

Python

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Avril 2009
    Messages : 9
    Par défaut passage de "self" à une méthode statique ?
    Bonjour,
    je préfère prévenir : je suis débutant en python. Toutefois j'ai une expérience de longue date en C et en C++. Du coup forcément j'essaie de reproduire les mécanismes dont j'ai l'habitude. Aussi : je m'excuse par avance si ma question est stupide.
    Voici un bout de code simple :
    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
     
    import matplotlib.pyplot as plt
    import numpy as np
    import Tkinter as tk
    import matplotlib.figure as mplfig
    import matplotlib.backends.backend_tkagg as tkagg
    pi = np.pi
     
     
    class App(object):
        def __init__(self, master):
            self.master = master
            self.fig = mplfig.Figure(figsize=(3, 3))  
            self.ax = self.fig.add_axes([0.125, 0.125, 0.75, 0.75], polar=True)  
            self.canvas = tkagg.FigureCanvasTkAgg(self.fig, master=master)  
            self.ax.grid(True)
            self.gridIsOn = True;
    #
             N = 5
            theta = np.arange(0.0, 2 * pi, 2 * pi / N)
            radii = np.arange(10.0,50, 40 / N) #[5.0,10.0,20.0,30.0,40.0 ]
            width = [2 * pi / (N)] * 5
            bars = (
                # self.ax.bar(0, 20, width=2 * pi, linewidth=0) +
                self.ax.bar(theta, radii, width))#, bottom=0.2))
            cmap = plt.get_cmap('jet')
             for r, bar in zip(radii, bars):
                bar.set_facecolor(cmap(r / 50.))
                bar.set_alpha(0.5)
             self.ax.set_xticklabels([])
            self.ax.set_yticklabels([])
             self.canvas.get_tk_widget().pack()
            self.canvas.draw()
            ### UN MORCEAU DU PROBLEMEE
            self.b = tk.Button(master, text="OK", command=App.ButtonCall(self))
            self.b.pack()
        @staticmethod
        def ButtonCall(o):  ## ICI ON EST EN PLEIN DANS LE PROBLEME
            print ("click!");
         #   if o.gridIsOn==True:
         #       o.gridIsOn=False;
         #   else:
         #        o.gridIsOn=True;
          #  o.ax.grid(o.gridIsOn)
          #  o.canvas.draw()
     
     
     
    def main():
        root = tk.Tk()
        app = App(root)
        tk.mainloop()
     
    if __name__ == '__main__':
        main()


    Il s'agit juste d'un code qui embarque une figure Matplotlib dans un environnement Tk. J'ai un soucis avec le callback. J'ai besoin que le callback connaisse l'objet App. Aussi je passe "un pointeur" sur l'objet App, et "self" me parait une bonne idée pour çà (c'est ce que je fais à la ligne 35)
    Une fois que j'atteins le callback, tant que les lignes commentées sont commentées ca marche, j'ai bien des "click" qui s'affichent dans la console. Mais si j'accède à l'objet o (par exemple en décommentant les lignes sous le print, ligne 40 et suivantes), alors le callback affiche une fois "click" et ensuite l'application est bloquée.

    Qu'est-ce qui est incorrect ?

    D'avance merci ...

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 715
    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 715
    Par défaut
    Salut,

    Citation Envoyé par JoeDalton Voir le message
    Il s'agit juste d'un code qui embarque une figure Matplotlib dans un environnement Tk. J'ai un soucis avec le callback. J'ai besoin que le callback connaisse l'objet App. Aussi je passe "un pointeur" sur l'objet App, et "self" me parait une bonne idée pour çà (c'est ce que je fais à la ligne 35).
    Je ne vois pas trop comment votre code pourrait fonctionner: "command=App.ButtonCall(self)" appellera la méthode statique (à cause des ()) et puis c'est tout.
    Pourquoi ne pas écrire: "command=self.ButtonCall" ? - en virant @staticmethod -
    self.ButtonCall est une méthode "bound" à l'objet "self". Son premier argument sera le bon "self".

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Avril 2009
    Messages : 9
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Salut,



    Je ne vois pas trop comment votre code pourrait fonctionner: "command=App.ButtonCall(self)" appellera la méthode statique (à cause des ()) et puis c'est tout.
    Pourquoi ne pas écrire: "command=self.ButtonCall" ? - en virant @staticmethod -
    self.ButtonCall est une méthode "bound" à l'objet "self". Son premier argument sera le bon "self".

    - W
    Bonjour,
    et merci pour votre réponse. Je ne fais pas une différence immense entre ce que vous proposez et ce que j'ai fait ... dans un cas on a une méthode statique a laquelle on donne un pointeur sur objet, reste à la méthode statique à piocher ce dont elle a besoin dans l'objet. Dans l'autre on appelle une méthode de la classe (plus direct mais pas différent sauf si on joue avec l'encapsulation).
    J'étais parti la dessus car je pensais que le callback nécessitait une méthode statique (c'est habituel dans les frameworks utilisés en C++). C'est peut etre différent en python.

    Quoi qu'il en soit j'ai essayé de remplacer ces lignes par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
          #create button and place it with pack method
            self.b = tk.Button(master, text="OK", command=self.ButtonCall())
            self.b.pack()
      #  @staticmethod
        def ButtonCall(self):
            print ("click!",self.gridIsOn);
    jusqu'ici ca ne fonctionne pas mieux ...

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Avril 2009
    Messages : 9
    Par défaut
    ok autant pour moi, il fallait enlever les parenthèses :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            self.b = tk.Button(master, text="OK", command=self.ButtonCall)
    Cette fois çà fonctionne, meme si c'est pas totalement clair pour moi.

    Merci !

  5. #5
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 715
    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 715
    Par défaut
    Citation Envoyé par JoeDalton Voir le message
    Cette fois çà fonctionne, meme si c'est pas totalement clair pour moi.
    Il faut désapprendre C++ et c'est pas facile car Python est plein de faux amis.

    "command" attend un "callback", i.e. une fonction.
    La 'bound method" évite d'avoir à exprimer "j'appelle la fonction avec 'self' en argument".
    Ce n'est pas utile ici.
    Pour le faire, on peut écrire: "command = lambda s=self: App.ButtonCall(s)"
    "lambda" sert ici à fabriquer une fonction anonyme qui se contente d'appeler App.ButtonCall avec s en paramètre...
    Mais on a mis self dans ce s.

    "lambda" est très utile mais ici passer la "bound method" suffit.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Pour compléter les explications de Wiztricks :

    Python a été écrit en C par Guido Van Rossum dans le début des années 90, à peu près à la même époque où Bjärne Stroustrup mettait au point C++ avec ses collègues des Bell Labs.

    A l'époque, chacun définissait son propre pointeur d'instance de classe comme il le sentait.

    Pour G. Van Rossum, c'était le pointeur self, pour B. Stroustrup, c'était le pointeur this, mais au final, ces deux pointeurs référencent la même chose : l'instance de classe en cours d'utilisation ou de création.

    La méthode magique __init__() est par ailleurs le constructeur de la classe : chez Python, G. Van Rossum avait choisi de nommer le constructeur de classe de manière fixe, une bonne fois pour toutes, alors que B. Stroustrup avait fait le choix de répéter le nom de la classe pour indiquer qu'il s'agissait d'un constructeur.

    Je vous laisserais seul juge de la pertinence des choix effectués par l'un comme par l'autre.

    En C++, vous pouvez aussi écrire quelque chose de semblable qu'en Python, notamment pour ce qui concerne le rattachement d'un callback à une méthode de la classe appelante, la seule contrainte réelle étant de déclarer votre méthode de classe C++ en public, ce qui n'est pas nécessaire sous Python, puisque toutes les méthodes de classe sont public par défaut (sauf quelques subtilités dont je vous ferais grâce afin de ne pas vous embrouiller d'entrée de jeu).

    Si vous avez pratiqué C++ / Qt par exemple, cela se fait assez couramment avec connect() le mécanisme d'harmonisation "événementiel" des callbacks, sans devoir recourir à des méthodes statiques (juste avec les méthodes publiques de la classe et le pointeur this).

    Comme Python émane de C à la base, il fonctionne par références (qui sont en réalité des pointeurs C).

    Lorsque vous écrivez :

    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
    34
    35
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
     
    from tkinter import *
     
     
    class App (Tk):
     
        def __init__ (self):
     
            # super class inits
            Tk.__init__(self)
     
            # click button
     
            b = Button(self, text="Cliquez ici", command=self.ma_methode)
     
            b.pack(padx=20, pady=20)
     
        # end def
     
        def ma_methode (self):
     
            print("click !")
     
        # end def
     
    # end class App
     
     
    if __name__ == "__main__":
     
        App().mainloop()
     
    # end if
    Dans b = Button(self, text="Cliquez ici", command=self.ma_methode) vous retournez à l'argument de fonction command une référence à l'adresse mémoire où se trouve la méthode self.ma_methode.

    Si vous mettez des parenthèses après, c'est comme pour C et pour C++ : la méthode/fonction pointant à l'adresse contenue dans le pointeur sera appelée avec les arguments se trouvant à l'intérieur des parenthèses.

    Exemple, vous avez sans doute déjà entendu parler des pointeurs de fonction en C/C++ :

    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    #include <stdlib.h>
    #include <stdio.h>
     
    /*
        voici grosso modo (pour illustrer)
        comment Python traite le code suivant :
     
        class MaClasse:
            def methode (self):
                return 1
            # end def
        # end class
     
        print("resultat: {:03d}".format(MaClasse().methode()))
     
        en C, cela donnera :
    */
     
    typedef struct {
     
        int (* methode) (void);
     
    } MaClasse;
     
     
    int MaClasse_methode (void) {
     
        return 1;
    }
     
     
    int main (int argc, const char * argv[]) {
     
        MaClasse * self = (MaClasse *) malloc(sizeof(MaClasse));
     
        self->methode = MaClasse_methode;           /* référence adresse mémoire */
     
        printf("resultat: %03d", self->methode());  /* utilisation de la référence */
     
        free(self);
     
        return 0;
    }
    Au final, quand vous plongez dans les finesses du langage Python, vous vous apercevez que ce langage est une forme élaborée de C, une approche vraiment intéressante des abstractions de structures et de données que le mathématicien Guido Van Rossum et ses collègues ont mis au point et qui n'a rien à envier à C++ (pas même le côté "compilation"), enfin, ce dernier point de vue est strictement personnel, bien entendu.

    @+.

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Avril 2009
    Messages : 9
    Par défaut
    Merci pour ces considérations sur Python. Jusqu'ici mon incursion dans ce monde se fait sans trop de douleur, j'ai juste volontairement mis de côté les lambda fonctions, je vois mal "quand" cela devient incontournable. J'imagine que c'est plutot "pratique" dans certains cas, mais je suppose que ca mange du temps à l'exécution.

    Car oui pour moi : C++ a été concu pour la performance / temps d'exécution (y'a qu'à voir les prouesses que font les gens qui font des templates avancés / bibliothèque BOOST par exemple), je pense que python a plutot été conçu pour de la conception objet pure, sans pointeurs non-virtual notamment ;-)

    J'ai à nouveau une galère mais c'est pas un problème fondamental de python, ca concerne le multi-threading et Matplotlib. Je vais faire un autre post.

    En tout cas merci pour l'aide !

    ++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 24/10/2007, 11h01
  2. Exécution d'un Thread dans une méthode statique
    Par barbiche dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 03/05/2007, 14h25
  3. Réponses: 3
    Dernier message: 14/04/2007, 16h06

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