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 :

Proxy pour properties


Sujet :

Python

  1. #1
    Membre émérite
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Par défaut Proxy pour properties
    Salut à tous.

    Créer un proxy pour une méthode n'est pas difficile, mais qu'en est-il pour les proxys de properties ?

    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
    >>> class Prop(object):
    ...     def __init__(self):
    ...         self.__model = None
    ...     
    ...     def getModel(self):
    ...         return self.__model
    ...     
    ...     def setModel(self):
    ...         self.__model = model
    ...     
    ...     model = property(getModel, setModel)
    ... 
    >>> class Prox:
    ...     def __init__(self):
    ...         self.__prop = Prop()
    ...         
    ...         # On peu facilement faire des proxy pour fonctions
    ...         self.propGetModel = self.__prop.getModel
    ... 
    ...     # Comment faire un proxy pour les properties de self.__prop ?
    ...     # Autrement dit, comment emuler le code ci-dessous, mais version propre...
    ...     def getPropModel(self):
    ...         return self.__prop.model
    ...     
    ...     def setPropModel(self, new):
    ...         self.__prop.model = new
    ...     
    ...     propModel = property(getPropModel, setPropModel)

  2. #2
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Dans le cas présenté n'y a t'il pas moyen de procéder par héritage afin que le proxy hérite des propriétés ?

  3. #3
    Membre émérite
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Par défaut
    Dans ce cas-ci, effectivement, l'héritage est une bonne solution, mais dans le contexte dans lequel je suis, je n'y ai pas droit.

    Le contexte en question, c'est un pattern Observer, ou plus précisément du MVC.
    Par exemple, un widget Button sera lié à un ButtonModel, qui pourra être partagé avec d'autres Button. C'est ce qui m'empêche de me servir de l'héritage.

  4. #4
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Pourriez vous donner plus de détails sur la finalité, afin de vérifier qu'un proxy est bien une solution conceptuellement viable et qu'il n'en existe pas de meilleure ?

  5. #5
    Membre émérite
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Par défaut
    Voici un résumé de l'implémentation (la totale serait bcp trop longue).
    Elle se calque assez précisément sur le MVC de Swing, que j'apprécie beaucoup et qui me manque atrocement avec gtk.
    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
    class ButtonModel(object):
        def __init__(self, text):
            self.__text = text
     
     
        def getText(self):
            return self.__text
     
        def setText(self, new):
            self.__text = new
            self._fireChangeEvent()
     
        text = property(getText, setText)
     
     
        def _fireChangeEvent():
            # Methode qui envoie un event à chaque Observer enregistré
            # par leur methode stateChanged
     
    class Button:
        def __init__(self, model):
            self.__model = model
            self.__update()
     
        def stateChanged(self, e):
            self.__update()
     
        def __update(self):
            # Met a jour le label du bouton selon le modèle
            self.set_label(self.__model.text)
     
        # Il me faudrait ici une sorte de proxy de la property model.text
        # de manière à ce que le changement du label d'un bouton
        # soit répercuté sur tous les autres.

  6. #6
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Pas sûr que ce soit ça, mais une solution serait que :
    - tous les composants dont l'état doit être tracé soient "Observable" : le modèle et les boutons,
    - un contrôleur soit Observer de ceux-ci et demande aux autres contrôles, les boutons, de se mettre à jour, via "__update".

    Ainsi :
    - si le modèle est changé il prévient le contrôleur qui va invoquer la méthode "__update" de tous les boutons dont il a la charge,
    - si le texte d'un bouton est changé, le bouton prévient le contrôleur qui ira update le modèle, à partir de là c'est comme pour le cas précédent.

    Cependant si tous les boutons doivent être synchronisés, pourquoi peuvent-ils être modifiés indépendamment ?

  7. #7
    Membre émérite
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Par défaut
    Citation Envoyé par seriousme Voir le message
    - si le modèle est changé il prévient le contrôleur qui va invoquer la méthode "__update" de tous les boutons dont il a la charge,
    - si le texte d'un bouton est changé, le bouton prévient le contrôleur qui ira update le modèle, à partir de là c'est comme pour le cas précédent.
    C'est déjà ce qu'il se passe dans mon implémentation actuelle, à la seule différence que je n'ai pas eu besoin de rajouter un controleur entre les boutons et le modèle. Les boutons notifient eux-même le modèle, et le modèle fait de même pour les boutons. Je vois mal l'utilité d'un composant en plus dans tout ça.

    D'ailleurs c'est le principe d'un pattern Observer: les observers souscrivent à un sujet. Dans mon cas, les observers sont les boutons, et le sujet est le modèle.

    La seule chose que je cherche, c'est de ne pas devoir rajouter une property dans ma class Button:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Button: (suite...)
        def getText(self):
            return self.__model.text
     
        def setText(self, new):
            self.__model.text = new
     
        text = property(getText, setText)
    C'est ce code que je ne trouve pas propre que je veux éviter. Je voudrais quelque chose qui envoie directement de Button.text à ButtonModel.text. Je cherche du côté de __getattribute__, __get__ et __set__, mais je patauge un peu...

    Citation Envoyé par seriousme Voir le message
    Cependant si tous les boutons doivent être synchronisés, pourquoi peuvent-ils être modifiés indépendamment ?
    Ils ne peuvent justement pas être modifiés indépendemment... c'est là le but du modèle.

  8. #8
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Ils ne peuvent justement pas être modifiés indépendemment... c'est là le but du modèle.
    Dans ce cas il est possible de créer un macro-composant "MultiButton" qui va agir comme un container de boutons : les boutons ne doivent pouvoir être modifiés que par son intermédiaire, lui se chargeant de dispatcher les mises à jours du modèle des boutons et des changements de texte.
    Il peut même implémenter une partie de l'interface des "Button" : get/set Text par exemple.

  9. #9
    Membre émérite
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Par défaut
    Tu n'as pas l'air de bien comprendre ma question.

    Je ne cherche pas un moyen de synchroniser les boutons, ça j'ai, c'est simple et ça fonctionne.

    Je cherche simplement une solution pour éviter le code un peu sale que j'ai mis dans mon dernier post.

  10. #10
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Désolé pour l'insistance sur la partie conception mais trouver un "hack technique" à une mauvaise conception pose souvent des problèmes de maintenance et d'évolutivité.

    Or ici le fait que les boutons encapsulent leur modèle n'est pas forcément la meilleure solution :
    - d'une part un bouton a de par sa nature un "texte", donc il devrait avoir un attribut "text", hérité ou pas,
    - d'autre part si le modèle doit être appliqué à un ensemble de boutons il serait mieux d'externaliser cette responsabilité hors des boutons : le bouton ne doit pas avoir accès à son modèle, c'est un gestionnaire de modèle qui se chargera de l'appliquer, comme par exemple le macro-composant évoqué précedemment; cela permet un découplage complet entre modèle et bouton.

    Plus généralement, même s'il existe un moyen de forwarder comme vous le souhaitez, il faut éviter de trop reposer sur les features spécifiques à une implémentation afin de facilité la maintenance du code par des tiers.
    Par exemple ici s'il fallait migrer l'application vers Java, il faudrait soit modifier les entités métiers : ajouter un champ à "Button", soit trouver l'équivalent du forwarding.

    Donc conclusion : il n'est pas nécessaire de chercher un moyen de forwarder automatiquement, votre solution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Button:
        ...
        def getText(self):
            return self.__model.text
     
        def setText(self, new):
            self.__model.text = new
     
        text = property(getText, setText)
    étant même meilleure à long terme : que se passerait t'il si plus tard le "Button" devait ajouter des pré/post-traitements et ne pas seulement se contenter de forwarder ?
    Il faudrait revenir à cette solution : placer des getter/setter dans "Button".

  11. #11
    Membre émérite
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Par défaut
    Citation Envoyé par seriousme Voir le message
    Désolé pour l'insistance sur la partie conception mais trouver un "hack technique" à une mauvaise conception pose souvent des problèmes de maintenance et d'évolutivité.
    Je ne cherche pas un "hack technique" pour contrer une éventuelle mauvaise conception, mais une méthode pythonique pour l'intégrer, m'assurant d'avoir une maitenance plus facile.

    - d'une part un bouton a de par sa nature un "texte", donc il devrait avoir un attribut "text", hérité ou pas,
    C'est précisément dans son modèle que le bouton ira chercher le texte.

    - d'autre part si le modèle doit être appliqué à un ensemble de boutons il serait mieux d'externaliser cette responsabilité hors des boutons : le bouton ne doit pas avoir accès à son modèle, c'est un gestionnaire de modèle qui se chargera de l'appliquer, comme par exemple le macro-composant évoqué précedemment; cela permet un découplage complet entre modèle et bouton.
    Ce gestionnaire est une couche complètement superflue dans mon cas. Du moins de ce que je vois, j'ai peut-être raté certains aspects. Comparons les deux implémentations (dites moi ce que vous en pensez):
    - Dans mon implémentation actuelle, plusieurs boutons souscrivent directement à un même modèle.
    Enregistrer et désenregistrer un bouton d'un modèle est l'affaire d'un appel de méthode. Changer une propriété d'un modèle (et donc de ses boutons) est aussi un appel de méthode.
    Par contre, substituer un modèle par un autre pour tous les boutons du premier demande beaucoup d'opérations. Mais, dans le contexte d'une GUI, je n'en vois pas d'utilité, à priori.

    - Dans celle que vous proposez, et si j'ai bien compris, un modèle est lié au gestionnaire, auprès duquel plusieurs bouton ont souscrit.
    Enregistrer et retirer un bouton, même affaire, un appel de méthode. Changer la propriété du modèle, idem. (encore que cette fois il y a un intermédiaire).
    Substituer un modèle par un autre, de même, un seul appel de fonction (tiens, vous avez bien fait d'insister, j'ai fini par trouver un bon point).
    Néanmoins, comme dit plus haut, je vois mal dans quel cas ça pourrait servir sur une GUI.

    que se passerait t'il si plus tard le "Button" devait ajouter des pré/post-traitements et ne pas seulement se contenter de forwarder ?
    C'est quelque chose que je tiens à éviter justement, puisque seul le modèle devrait influer sur ces valeurs, puis ensuite signaler le changement aux boutons pour qu'ils se mettent à jour. Tout ça dans l'idée justement de créer un proxy simple de Button vers ButtonModel et faciliter la maintenance par après.



    Bon, je suis jeune développeur, et loin d'avoir tout vu. Mais... quand on me dit que quelque chose n'est pas correct, j'aime bien avoir tous les détails de mon erreur pour comprendre plus en profondeur. Et, cette fois, je comprends mal comment cette couche en plus pourrait être utile (dans mon cas bien entendu).

  12. #12
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    C'est précisément dans son modèle que le bouton ira chercher le texte.
    A priori le texte d'un bouton est une propriété inhérente qui ne devrait pas être externaliser.
    Cela est le cas dans la majorité (totalité ?) des libs de composition d'IHM : Java/Swing, ASP.Net/WebControls ...
    Pourquoi externaliser et ne pas suivre ce qui a, à priori, est bien conçu ?

    Pour aller plus loin le texte d'un bouton tient de sa sémantique, le "fond", son modèle de son apparence, la "forme".
    Si tous les boutons ont la même sémantique alors il faut qu'ils soient gérés ensemble explicitement, en les plaçant dans un container par exemple, et pas implicitement seulement via un système d'abonnement Observable/Observer.

    Ce gestionnaire est une couche complètement superflue dans mon cas.
    ...
    Néanmoins, comme dit plus haut, je vois mal dans quel cas ça pourrait servir sur une GUI.
    En effet si le développement en question n'est pas une lib graphique il est sans doute inutile de perdre du temps sur des conceptions évoluées.

    Quoi qu'il en soit, désolé de ne pas apporter de réponse au problème initial.

  13. #13
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Je ne suis pas sûr d'avoir tout compris, mais il y a une solution pour faire partager une valeur à l'ensemble des instances d'une même classe sans recourir aux héritages: il faut que l'attribut appartienne à la classe elle-même et non à ses instances.

    Pour cela, il faut déclarer l'attribut à la racine de la classe et sans self, et s'y référer en le préfixant par le nom de la classe.

    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
     
    class Model(object):
     
        msg = "texte"
     
        def donnemsg(self):
            return Model.msg
     
    x = Model()
    y = Model()
    z = Model()
     
    print x.donnemsg(), y.donnemsg(), z.donnemsg()
     
    Model.msg = "toto"
    print Model.msg
     
    print x.donnemsg(), y.donnemsg(), z.donnemsg()
    Ce qui affiche:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    texte texte texte
    toto
    toto toto toto
    On voit bien que le changement de l'attribut msg, appelé par Model.msg, est partagé par les 3 instances de la classe Model.

    (Et désolé si je suis à côté de la question).

    Tyrtamos

  14. #14
    Membre émérite
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Par défaut
    Ce n'est pas encore ça hélas, puisqu'il peut y avoir plusieurs "groupes" de boutons, et que donc des propriétés uniquent ne suffisent pas. Ta proposition peut peut-être se développer par contre, j'y repenserai plus tard. Merci


    Je voudrais en revenir à cette histoire d'observer etc. dont je parlais avec seriousme, et de ce fait dériver du sujet premier du topic.
    Aujourd'hui en cours de DB, nous avons vu les embryons de la "normalisation", et par conséquent reparlé des tables de relation.

    En revoyant ça, j'ai directement fait un lien entre ces tables de relation et ce dont on a discuté ici. Et, s'opposant à tout cela, les relations de type Many to Many que l'on a vu au cours de POO.

    Je m'explique: (ça sera très certainement flou, puisque même dans ma tête c'est embué, veuillez m'en excuser)

    Dans l'environnement de DB, une relation que l'on qualifie de "m à n" (soit l'équivalent de Many to Many) est matérialisée par 3 tables:
    Deux que nous appellerons les sujets, et la troisième qui lie un sujet à un autre.

    Or, au cours de POO, les relations Many to Many sont stockées dans des List, Map ou autres, et ce directement dans les objets concernés. (Comme mon implémentation actuelle)

    Pourtant, comme vu au cours de Math, de DB et comme suggéré plus haut, il est possible de créer des objets intermédiaires aux sujets, qui lient les deux, rendant par ce fait les sujets (presque) totalement indépendants.

    Un peu piqué au vif par ces questions qui se posaient, je suis allé trouver mon prof de POO pour lui demander ce qui était conceptuellement le plus correct, lui expliquant que j'avais implémenté un pattern observer avec des Model liés en One to Many à des boutons, et puis présentant l'alternative suggérée plus haut.

    Il m'a répondu que cette suggestion était en réalité le pattern complet (aucun site que j'aie visité ne m'a proposé le modèle complet donc, mais soit...), et m'a aussi dit qu'on faisait des associations soit comme vu au cours de POO(Many to Many directement dans les objets), soit comme au cours de Math (une relation externe).

    Un peu vexé de ne pas avoir vu l'observer complet, je suis allé emprunter dard-dard une bonne brique sur les patterns à la biblio, dont j'espère qu'il m'éclaircira un peu la pensée, mais...

    Quid alors ? Où et quand utiliser un type d'association ou l'autre ?

    Je vois bien que l'un est plus léger, l'autre plus flexible, mais au delà de ça, ça reste assez flou dans mon esprit. Pourriez-vous me donner des infos pour clarifier tout ça ?

Discussions similaires

  1. Proxy pour terminal server
    Par ramzi_zi dans le forum Windows
    Réponses: 3
    Dernier message: 29/01/2008, 10h01
  2. Réponses: 7
    Dernier message: 11/12/2007, 03h16
  3. [ISA SERVER 2000] Configurer le proxy pour autoriser les connexions P2P
    Par senator dans le forum Serveurs (Apache, IIS,...)
    Réponses: 2
    Dernier message: 19/01/2007, 10h57
  4. [design][swing] design pour property panel réutilisable
    Par mlequim dans le forum AWT/Swing
    Réponses: 7
    Dernier message: 26/11/2005, 22h07
  5. Connexion derrière un proxy pour Firebird ???
    Par .:morgoth:. dans le forum Connexion aux bases de données
    Réponses: 8
    Dernier message: 17/02/2005, 09h32

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