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 :

add attribs & methods


Sujet :

Tkinter Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Profil pro
    Développeur en systèmes embarqués retraité
    Inscrit en
    Mars 2006
    Messages
    952
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2006
    Messages : 952
    Par défaut add attribs & methods
    Salut,

    Pour un projet avec du drag & drop, je dois rajouter des attributs et des méthodes à un ensemble de classes tkinter. Dans l'exemple ci-dessous je rajoute l’attribut dummyVar et la méthode dummyFunc aux classes Tk et Button. La façon de faire avec "exec" étant à mon sens très propice aux critiques, je me demandais si quelqu'un avait quelquechose de plus conventionnel?

    A+

    Pfeuh

    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
     
    class_template = """
    class DND(_classname_):
        def __init__(self, *args, **kwds):
            _classname_.__init__(self, *args, **kwds)
            self.dummyVar = None
        def dummyFunc(self):
            return self.dummyVar.upper()
    """
     
    def getDND(classname, *args, **kwds):
        exec class_template.replace('_classname_', classname)
        obj = DND(*args, **kwds)
        return obj
     
    if __name__ == "__main__":
     
        try:import Tkinter
        except: import tkinter as Tkinter
     
        win = getDND('Tkinter.Tk')
        bt = getDND('Tkinter.Button', win, text='DND object', width=50, height=3)
        bt.grid()
        # test
        assert win.dummyVar == None
        win.dummyVar = 'azerty'
        assert win.dummyFunc() == 'AZERTY'
        assert bt.dummyVar == None
        bt.dummyVar = 'qwerty'
        assert bt.dummyFunc() == 'QWERTY'
     
        win.mainloop()

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

    L'idée de base est "bonne": getDND "fabrique" une sous-classe de l'objet Tk qu'on lui donne... mais "laissez à l’interpréteur le soin de se débrouiller avec les strings des scripts..."

    Ce qui donne:
    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
    classmap = {}  # stores class.
     
    def factory(base):
     
        class _wraps_(base, object):
            def __init__(self, *args, **kwds):
                base.__init__(self, *args, **kwds)
                self.dummyVar = None
            def dummyFunc(self):
                return self.dummyVar.upper()
     
        name = 'DND_%s' % base.__name__
        cls = classmap.get(name, None)
        if not cls:
            cls  = type(name, (_wraps_,), {})  
            classmap[name] = cls
        return cls
    notes:
    1. Normalement "classmap" est le dict d'un "module"
    2. Ca fonctionne sous Python 2, version ou Tkinter n'est pas "new-style class". Normalement le {} de "type" devrait pouvoir contenir la déclaration des "fonctions", et bases pourrait être réduit à (base,)

    Pour ce qui est de "l'utilisation", j'ai séparé construction de la classe et construction de l'instance...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    if __name__ == "__main__":
     
        try:
            import Tkinter as tk
        except:
            import tkinter as tk
     
        win = factory(tk.Tk)()
        bt = factory(tk.Button)(win, text='DND object', width=50, height=3)
        bt.grid()
    Bon courage,
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre Expert
    Profil pro
    Développeur en systèmes embarqués retraité
    Inscrit en
    Mars 2006
    Messages
    952
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2006
    Messages : 952
    Par défaut
    Merci wiztricks, c'est exactement ce qu'il me fallait.

    Citation Envoyé par wiztricks Voir le message
    mais "laissez à l’interpréteur le soin de se débrouiller avec les strings des scripts..."
    Pour cela, il m'eût fallu des connaissances que je n'ai pas...

    A+

    Pfeuh

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

    Une autre façon de faire "pas très naturelle" pour ceux qui viennent des langages POO compilés est le "patch" dynamique des classes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def dummyFunc(self):
            return self.dummyVar.upper()
     
    def factory(cls):
        if not hasattr(cls, 'dummyVar'):
            setattr(cls, 'dummyVar', None)
            setattr(cls, 'dummyFunc', dummyFunc)
        return cls
    On passe toujours par "factory". Mais on "taggue" la mise à jour de la classe via l'existence d'un attribut.
    note: j'ai le souvenir d'une entrée qui wrappait les classes tk mais je ne la retrouve pas.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre Expert
    Profil pro
    Développeur en systèmes embarqués retraité
    Inscrit en
    Mars 2006
    Messages
    952
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2006
    Messages : 952
    Par défaut
    Salut,
    Citation Envoyé par wiztricks Voir le message
    Une autre façon de faire "pas très naturelle"
    Je trouve que c'est une super idée, elle me semble même très naturelle dans la démarche Par contre, sauf erreur, on ne travaille pas sur une copie de la classe mais sur l'original, donc une fois qu'elle est modifiée, l'original est définitivement perdu.

    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
     
    def dummyFunc(self):
            return self.dummyVar.upper()
     
    def factory(cls):
        if not hasattr(cls, 'dummyVar'):
            setattr(cls, 'dummyVar', None)
            setattr(cls, 'dummyFunc', dummyFunc)
        return cls
     
    if __name__ == "__main__":
     
        import Tkinter
     
        root = Tkinter.Tk()
        WINDOW = factory(Tkinter.Toplevel)
     
        win1 = WINDOW()
        win1.dummyVar = 'azerty'
        assert win1.dummyFunc() == 'AZERTY'
     
        win2 = Tkinter.Toplevel()
        win2.dummyVar = 'uiop'
        assert win2.dummyFunc() == 'UIOP'

  6. #6
    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
    Bonsoir,

    Citation Envoyé par pfeuh Voir le message
    Je trouve que c'est une super idée, elle me semble même très naturelle dans la démarche
    Le fait de modifier ('patcher') la classe elle même ? Moi pas.

    Pour un code 'simple' cela passe mais la solution 'métaclass factory' proposé par wiztricks en premier me semble bien plus propre.
    Votre choix vient il de la simplicité du second code ? Dans ce cas vous pouvez réduire le premier (désolé pour le temps passé wiztricks)
    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
    def factory(base_class, cls_opts):
        cls = type(base_class)
        return cls('DND_%s' % base_class.__name__, (base_class,), cls_opts)
     
    if __name__ == "__main__":
     
        try:
            import Tkinter as tk
        except:
            import tkinter as tk
     
        def dummyFunc(self):
            return self.dummyVar.upper()
     
        options = {'dummyVar': None, 'dummyFunc': dummyFunc}
     
        win = factory(tk.Tk, options)
        fen = win()
        fen.dummyVar = "azerty"
        print(fen.dummyFunc())
    ou
    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
    def factory(base_class):
        def dummyFunc(self):
            return self.dummyVar.upper()
     
        cls = type(base_class)
        return cls('DND_%s' % base_class.__name__, (base_class,),
                   {'dummyVar': None, 'dummyFunc': dummyFunc})
     
    if __name__ == "__main__":
     
        try:
            import Tkinter as tk
        except:
            import tkinter as tk
     
        win = factory(tk.Tk)
        fen = win()
        fen.dummyVar = "azerty"
        print(fen.dummyFunc())
    (Vous remarquerez au passage la souplesse du code. Pour type voir (*))

    A vrais dire c'est ce qui était fait dans new.py avec type.
    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
    import Tkinter as Tk
    from new import classobj
     
    def factory(base_class):
        def dummyFunc(self):
            return self.dummyVar.upper()
     
        return classobj('DND_%s' % base_class.__name__,
                        (base_class,),
                        {'dummyFunc': dummyFunc, 'dummyVar': None})
     
    root = Tk.Tk()
    dnd_top = factory(Tk.Toplevel)()
    dnd_top.dummyVar = "azerty"
    print(dnd_top.dummyFunc())
    tk_top = Tk.Toplevel()
    print(hasattr(tk_top, 'dummyFunc'))
    root.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
    25
    26
    27
    28
    import Tkinter as Tk
     
    # +- from new import classobj. deprecated since Python 2.6,
    # removed in Python 3.0
    # ie from types import ClassType as classobj
    #
    # types.ClassType code
    class _C:
        def _m(self):
            pass
    #
    classobj = type(_C)
    # +- use the types module instead.
    def factory(base_class):
        def dummyFunc(self):
            return self.dummyVar.upper()
     
        return classobj('DND_%s' % base_class.__name__,
                        (base_class,),
                        {'dummyFunc': dummyFunc, 'dummyVar': None})
     
    root = Tk.Tk()
    dnd_top = factory(Tk.Toplevel)()
    dnd_top.dummyVar = "azerty"
    print(dnd_top.dummyFunc())
    tk_top = Tk.Toplevel()
    print(hasattr(tk_top, 'dummyFunc'))
    root.mainloop()
    Ceci dit vous voulez passer outre un héritage 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
    try:
        import Tkinter as Tk
    except:
        import tkinter as Tk
     
    class Dnd_Toplevel(Tk.Toplevel):
        def __init__(self, *args, **kwargs):
            Tk.Toplevel.__init__(self, *args, **kwargs)
            dummyVar = None
        def dummyFunc(self):
            return self.dummyVar.upper()
     
    root = Tk.Tk()
    top = Dnd_Toplevel(root)
    top.dummyVar = "azerty"
    print(top.dummyFunc())
    Et vous vous en êtes pas mal tiré avec exec (Non, exec is not . C'est du Python)/replace. Bien vu.

    @+

    * type, le built-in 'usine' de (méta)classe.
    type(nom_de_la_classe, tuple des parents (tuple vide possible si pas de parent), dico des attributs/méthodes a ajouter)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    >>> Foo = type('new_class', tuple(), {})
    >>> Foo
    <class '__main__.new_class'>
    Edit pour enlever une grosse bêtise print(fen.__class__ == type(fen)).

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 08/04/2010, 11h41
  2. Methode add d'ArrayList
    Par davdoo91 dans le forum Collection et Stream
    Réponses: 4
    Dernier message: 28/02/2009, 16h50
  3. [A-03] Methode Add et Item d'une collection
    Par elfiestador dans le forum VBA Access
    Réponses: 4
    Dernier message: 09/12/2008, 10h18
  4. [Excel] Add method of chartObjects class failed
    Par bougo dans le forum Windows Forms
    Réponses: 1
    Dernier message: 14/06/2007, 13h39
  5. Réponses: 4
    Dernier message: 14/05/2007, 10h45

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