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 :

Factory pour un modèle "d'addons"


Sujet :

Python

  1. #1
    Membre averti

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2007
    Messages
    186
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Alpes de Haute Provence (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2007
    Messages : 186
    Points : 399
    Points
    399
    Par défaut Factory pour un modèle "d'addons"
    Je suis en train de réfléchir a un système permettant a des contributeurs de modifier le comportement de certaines classes d'une application en écrivant des classes filles. Voici un code d'exemple:

    Le but est de permettre a des contributeur de modifier le comportement de BaseWorker ou BaseWarrior. Les classes concernés:

    baseobjects.py
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class BaseBug(object):
        def move(self, x, y):
            print 'move', x, y
     
    class BaseWorker(BaseBug):
        def work(self):
            print 'work'
     
    class BaseWarrior(BaseBug):
        def fight(self):
            print 'fight'
    La "Factory" écrite pour permettre ce comportement: Un singleton qui lorsque on lui demande une classe construit un classe pour l'occasion qui hérite (héritage multiple) de toutes les réécritures présente dans les addons.

    factory.py
    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
    class Factory:
        class __Factory:
     
            def __init__(self):
                self._extend_registry = {}
                self._class_registry = {}
     
            def extend(self, object_name, theclass):
                if object_name not in self._extend_registry:
                    self._extend_registry[object_name] = []
                self._extend_registry[object_name].append(theclass)
     
            def get_class(self, object_name):
                if object_name not in self._class_registry:
                    # Construction d'une classe etendue a partir des sous classes existantes
                    self._class_registry[object_name] = type('Final'+object_name, tuple(self._extend_registry[object_name]), {})
                return self._class_registry[object_name]
     
        instance = None
     
        def __init__(self):
            if not Factory.instance:
                Factory.instance = Factory.__Factory()
        def __getattr__(self, name):
            return getattr(self.instance, name)
    Des surcharges, sortes "d'addons" ajoutable/enlevable par l'utilisateur:

    spaceobjects.py
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from factory import Factory
    from baseobjects import BaseWorker, BaseWarrior
     
    class SpaceWarrior(BaseWarrior):
        def fight(self):
            super(SpaceWarrior, self).fight()
            print 'Se bat dans l\'espace'
     
    factory = Factory()
    factory.extend('Warrior', SpaceWarrior)
    armedobjects.py
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from factory import Factory
    from baseobjects import BaseWorker, BaseWarrior
     
    class ArmedWarrior(BaseWarrior):
        def fight(self):
            super(ArmedWarrior, self).fight()
            print 'tire un coup de fusil'
     
    factory = Factory()
    factory.extend('Warrior', ArmedWarrior)
    et l'utilisation du tout:

    main.py
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    from factory import Factory
    import spaceobjects
    import armedobjects
     
    factory = Factory()
     
    warrior = factory.get_class('Warrior')()
    warrior.fight()
    warrior.fight() produit:
    fight
    tire un coup de fusil
    Se bat dans l'espace
    Avez-vous déjà implémenter quelque-chose dans le genre ? L'ais-je implémenté d'une façon intelligente ou je cours a la catastrophe ? N'y aurais t-il pas un patron de conception existant pour ce cas de figure ?

  2. #2
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Sans avoir épluché ton code, il me semble que ce que tu cherches à faire correspond à la notion de "métaclasse".

    Je ne suis pas (et de loin) expert en métaclasses, mais le concept est intéressant. En gros, les classes Python "nouveau style" sont toutes construites sur la base de la métaclasse "type". Mais cette dépendance est plus qu'un simple héritage: c'est la métaclasse qui détermine la manière dont les classes qui en dépendent seront construites et fonctionneront.

    Ainsi, on peut créer une nouvelle métaclasse sur "type", et élargir/modifier/limiter les classes qui seront construites dessus.

    Pour aller plus loin: il y a pas mal d'articles, y compris en français, sur le sujet (voir "python métaclasse" avec google), à commencer par https://fr.wikipedia.org/wiki/M%C3%A9taclasse.

    A mon avis, compte tenu de ce que tu cherches, tu aurais intérêt à creuser un peu dans cette direction (mais je n'ai pas dit que ce serait simple ).
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

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

    Ce concept tient parfaitement la route tant qu'on "étend" une superstructure donnée avec des classes filles de même niveau.

    Contre-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
    34
    35
    36
    37
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    from factory import Factory
     
    class BaseBug(object):
        def move(self, x, y):
            print 'move', x, y
     
    class BaseWarrior(BaseBug):
        def fight(self):
            print 'fight'
     
    class SpaceWarrior (BaseWarrior):
        def fight(self):
            super(SpaceWarrior, self).fight()
            print 'Se bat dans l\'espace'
     
    class TotoWarrior (SpaceWarrior):
        def fight(self):
            super(TotoWarrior, self).fight()
            print 'fait toto!'
     
    class ArmedWarrior (BaseWarrior):
        def fight(self):
            super(ArmedWarrior, self).fight()
            print 'tire un coup de fusil'
     
    factory = Factory()
     
    factory.extend('Warrior', SpaceWarrior)
    factory.extend('Warrior', ArmedWarrior)
     
    factory.extend('Warrior', TotoWarrior) # MRO !
     
    warrior = factory.get_class('Warrior')()
    warrior.fight()
    la méthode extend() est sensible à l'ordre d'enregistrement des classes.

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    factory.extend('Warrior', SpaceWarrior)
    factory.extend('Warrior', ArmedWarrior)
    ne réagit pas comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    factory.extend('Warrior', ArmedWarrior)
    factory.extend('Warrior', SpaceWarrior)
    donc le déroulement du flux programmatique en sera altéré.

    bien sûr, si c'est sans conséquence sur le résultat attendu...

    il faut tenir compte aussi du MRO (Method Resolution Order) et donc du niveau de dérivation de la classe ancêtre (ici, niveau 1 : classe ancêtre > sous-classe directe).

    ça plante dès le niveau 2 (classe ancêtre > sous-classe > sous-sous-classe).

    mais bon, quel intérêt d'inclure des niveaux hétérogènes ? à étudier de plus près.

    ce concept m'a l'air un petit peu tiré par les cheveux, mais pourquoi pas, après tout ?

    @+.

  4. #4
    Invité
    Invité(e)
    Par défaut
    Pour le singleton Factory, voici un design pattern intéressant : https://fr.wikipedia.org/wiki/Single...eption)#Python

    @+.

  5. #5
    Membre averti

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2007
    Messages
    186
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Alpes de Haute Provence (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2007
    Messages : 186
    Points : 399
    Points
    399
    Par défaut
    Je vais regarder de plus près les metaclass, mais pour l'instant le concept a l'air un peu compliqué" en effet !
    Pour le singleton Factory je vais regarder aussi.

    Pour l'ordre de résolution du MRO je me creuse la tête pour essayer de mettre en évidence un cas de figure ou ça pose problème mais pour l'instant je n'en ai pas. Bien que ça semble un peu inévitable non ?

    Pour ce qui est du problème d'avoir deux "extensions" de classes qui se confronterai lors de la construction de la classe "Finale" j'ai implémenté ce principe: Une classe étendu dans un addons précise a la Factory quelle classe elle étend. Afin que la Factory sache qu'elle doit la remplacer (puisque étendu):

    factory.py
    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 Factory:
        class __Factory:
            def __init__(self):
                self._extend_registry = {}
                self._class_registry = {}
            def extend(self, object_name, extend_class, parent_class):
                if object_name not in self._extend_registry:
                    self._extend_registry[object_name] = []
                try:
                  # Si la classe qui étend étend une classe qui a déjà été étendu elle est remplacé
                  index_of_existent_extend = self._extend_registry[object_name].index(parent_class)
                  self._extend_registry[object_name][index_of_existent_extend] = extend_class
                except ValueError:
                  self._extend_registry[object_name].append(extend_class)
     
            def get_class(self, object_name):
                if object_name not in self._class_registry:
                    # Construction d'une classe etendue a partir des sous classes existantes
                    self._class_registry[object_name] = type('Final'+object_name, tuple(self._extend_registry[object_name]), {})
                return self._class_registry[object_name]
     
        instance = None
     
        def __init__(self):
            if not Factory.instance:
                Factory.instance = Factory.__Factory()
        def __getattr__(self, name):
            return getattr(self.instance, name)
    Du coups on peux étendre une classe présente dans un addons (et faire des addons d'addons):

    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
    56
    57
    58
    59
    60
    61
    62
    63
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    from factory import Factory
     
    class BaseBug(object):
        def __init__(self):
            self.hits = []
        def move(self, x, y):
            print 'move', x, y
        def how_feel(self):
            print "i'm ", self.hits
     
    class BaseWarrior(BaseBug):
        def fight(self):
            print 'fight'
        def hit(self, him):
            self.fight()
            him.hits.append('ematome')
            return him
     
    class SpaceWarrior (BaseWarrior):
        def fight(self):
            super(SpaceWarrior, self).fight()
            print 'Se bat dans l\'espace'
     
    class ArmedWarrior (BaseWarrior):
        def fight(self):
            super(ArmedWarrior, self).fight()
            print 'tire un coup de fusil'
        def hit(self, him):
            him = super(ArmedWarrior, self).hit(him)
            him.hits.append('perfore')
            return him
     
    class TotoWarrior (ArmedWarrior):
        def fight(self):
            super(TotoWarrior, self).fight()
            print 'fait toto!'
     
    class ArmedWarrior2 (ArmedWarrior):
        def how_feel(self):
            try:
                self.hits.index('perfore')
                print 'Damned! je suis perfore !'
            except ValueError:
              super(FooWarrior, self).how_feel()
     
    factory = Factory()
     
    factory.extend('Warrior', SpaceWarrior, BaseWarrior)
    factory.extend('Warrior', ArmedWarrior, BaseWarrior)
     
    factory.extend('Warrior', TotoWarrior, ArmedWarrior)
    factory.extend('Warrior', ArmedWarrior2, ArmedWarrior)
     
    some_bug_hited = factory.get_class('Warrior')()
     
    warrior = factory.get_class('Warrior')()
    warrior.hit(some_bug_hited)
     
    print 'and hited bug say:'
    some_bug_hited.how_feel()
    qui produit:
    fight
    tire un coup de fusil
    fait toto!
    Se bat dans l'espace
    and hited bug say:
    Damned! je suis perfore !
    Mais je me demande quand même toujours un peu ce que ça va donner dans un contexte réel ^^

  6. #6
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par buxbux Voir le message
    Mais je me demande quand même toujours un peu ce que ça va donner dans un contexte réel ^^
    Effectivement.

    Dans __Factory.extend(), vous pouvez extraire la classe parente directement de extend_class, exemple générique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    class Toto (object): pass
     
    class Tutu (Toto): pass
     
    print Toto.__bases__, Tutu.__bases__
     
    a = Tutu()
     
    print a.__class__.__bases__
    J'ai trouvé object.__class__.__bases__ en fouinant du côté des MRO, justement : https://www.python.org/download/releases/2.3/mro/

    Le sujet débattu sur cette page est intéressant.

    Té, je viens de trouver ça, aussi : https://docs.python.org/2/library/st...lass.__bases__

    Pas dégueu non plus. ^^

    @+.

  7. #7
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 811
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 811
    Points : 7 096
    Points
    7 096
    Par défaut
    Bonsoir,

    Tim Peters, un patron du langage dit cela un jour

    Citation Envoyé par Tim Peters
    Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  8. #8
    Membre averti

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2007
    Messages
    186
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Alpes de Haute Provence (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2007
    Messages : 186
    Points : 399
    Points
    399
    Par défaut
    @tarball69 J'avais commencé a modifier Factory en exploitant __bases__ au départ. Mais je me suis demandé comment prévoir le cas ou la classe qui étend hériterait de plusieurs classes. Ça ma semblé plus sûr de faire préciser manuellement quelle classe on veux étendre.

    @fred1599 intéressant !

  9. #9
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 811
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 811
    Points : 7 096
    Points
    7 096
    Par défaut
    Le but est de permettre a des contributeur de modifier le comportement de BaseWorker ou BaseWarrior
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import types
     
    class BaseWorker:
        @classmethod
        def addMethod(cls, func):
            return setattr(cls, func.__name__, types.MethodType(func, cls))
     
    def method(self, n):
        return n
     
    BaseWorker.addMethod(method) # ajout de la méthode method à la classe BaseWorker
     
    b = BaseWorker() # instanciation
    print(b.method(5)) # exécution de la nouvelle méthode
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  10. #10
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par buxbux Voir le message
    @tarball69 J'avais commencé a modifier Factory en exploitant __bases__ au départ. Mais je me suis demandé comment prévoir le cas ou la classe qui étend hériterait de plusieurs classes. Ça ma semblé plus sûr de faire préciser manuellement quelle classe on veux étendre.
    Effectivement, c'est plus sûr, mais :

    1. Ca implique des arguments supplémentaires à déclarer à chaque fact.extend() donc plus de code ;

    2. Statistiquement parlant, vous aurez 90% de cas avec une seule classe ancêtre ;

    3. donc on peut mettre l'argument parent_class en facultatif genre parent_class=None puis gérer if parent_class is None: extraire object.__class__.__bases__[0] en automatique ;

    C'est une idée pour alléger le côté déclaratif des appels fact.extend().

    @+.

  11. #11
    Membre averti

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2007
    Messages
    186
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Alpes de Haute Provence (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2007
    Messages : 186
    Points : 399
    Points
    399
    Par défaut
    Citation Envoyé par tarball69 Voir le message
    Effectivement, c'est plus sûr, mais :

    1. Ca implique des arguments supplémentaires à déclarer à chaque fact.extend() donc plus de code ;

    2. Statistiquement parlant, vous aurez 90% de cas avec une seule classe ancêtre ;

    3. donc on peut mettre l'argument parent_class en facultatif genre parent_class=None puis gérer if parent_class is None: extraire object.__class__.__bases__[0] en automatique ;

    C'est une idée pour alléger le côté déclaratif des appels fact.extend().

    @+.
    Bien vu ! Je rajouterais même ceci:

    if parent_class is None and len(extend_class.__bases__) > 1:
    raise UneErreur("veuillez préciser la classe surchargé avec le paramètre parent_class")

    Pour les 10 % et on a un truc complet :p

    Citation Envoyé par fred1599 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import types
     
    class BaseWorker:
        @classmethod
        def addMethod(cls, func):
            return setattr(cls, func.__name__, types.MethodType(func, cls))
     
    def method(self, n):
        return n
     
    BaseWorker.addMethod(method) # ajout de la méthode method à la classe BaseWorker
     
    b = BaseWorker() # instanciation
    print(b.method(5)) # exécution de la nouvelle méthode
    D'après ce que je comprend cette implémentation permettrai d'ajouter et remplacer des méthodes de la classes. Cependant si l'on souhait modifier le comportement d'une méthode existante il faudra la réécrire complètement non ? On perd pas mal de choses que l'on peu faire avec une classe fille il me semble.

  12. #12
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 811
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 811
    Points : 7 096
    Points
    7 096
    Par défaut
    Cependant si l'on souhait modifier le comportement d'une méthode existante il faudra la réécrire complètement non ?
    Pour modifier le comportement d'une méthode il faut déjà vérifier que cette méthode existe, et utiliser addMethod pour la réécrire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import types
     
    class BaseWorker:
        @classmethod
        def addMethod(cls, func):
            return setattr(cls, func.__name__, types.MethodType(func, cls))
        @classmethod
        def modifyMethod(cls, func):
            if func.__name__ in cls.__dict__:
                BaseWorker.addMethod(func)
    Tout simplement, non?
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  13. #13
    Membre averti

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2007
    Messages
    186
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Alpes de Haute Provence (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2007
    Messages : 186
    Points : 399
    Points
    399
    Par défaut
    Citation Envoyé par fred1599 Voir le message
    Pour modifier le comportement d'une méthode il faut déjà vérifier que cette méthode existe, et utiliser addMethod pour la réécrire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import types
     
    class BaseWorker:
        @classmethod
        def addMethod(cls, func):
            return setattr(cls, func.__name__, types.MethodType(func, cls))
        @classmethod
        def modifyMethod(cls, func):
            if func.__name__ in cls.__dict__:
                BaseWorker.addMethod(func)
    Tout simplement, non?
    Ce que je veux dire c'est que ce n'est pas très DRY. Si je veux modifier le comportement d'un méthode de BaseWorker déjà existante, je dois refournir a addMethod une fonction qui réécrit toute la méthode puisqu'elle la remplacera.

  14. #14
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 811
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 811
    Points : 7 096
    Points
    7 096
    Par défaut
    Alors tu vas fournir quoi d'autre qu'une méthode pour en remplacer une ?

    Tu vas fournir quoi comme information pour modifier le contenu d'une méthode ?

    Je commence à avoir du mal à comprendre ce que tu souhaites... surcharger une méthode de classe ? Recréer une classe Fille + surcharge méthode classe mère = plus lourd, si c'est ça que tu souhaitais faire.
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  15. #15
    Membre averti

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2007
    Messages
    186
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Alpes de Haute Provence (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2007
    Messages : 186
    Points : 399
    Points
    399
    Par défaut
    Je crois qu'il y a confusion, quand je dit "modifier le comportement" je parle d'héritage.
    Voici une illustration de mes propos quand à ta solution:

    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
    class Warrior(BaseWorker):
      def do_something(self):
        print('done something1')
        # ...
        print('done something5')
        return 'done!'
     
    def do_something(self):
      print('done something1')
      # ...
      print('done something5')
      print('done something and another again')
      return 'done!'
     
    Warrior.modifyMethod(do_something)
    warrior = Warrior()
    warrior.do_something()
    De cette manière, lorsque l'on veut spécialiser le comportement d'une méthode, il faut réécrire toute la méthode. On perd des avantage de l'héritage comme de ne pas répéter le code, de supporter l'évolution des classes parentes, etc

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Warrior(BaseWorker):
      def do_something(self):
        print('done something1')
        # ...
        print('done something5')
        return 'done!'
     
    class WarriorEvolued(Warrior):
      def do_something(self):
        done = super(WarriorEvolued, self).do_something()
        print('done something and another again')
        return done
    Ta solution est fonctionnelle, mais si je l'utilise dans mon contexte, c'est a dire proposer la spécialisation de classes dans des "addons", chaque addons qui écrase une méthode de classe écrase les modifications potentielles d'un autre addon.

Discussions similaires

  1. REQ : Algo pour vérification saisie du "Numero TVA"
    Par Eric.H dans le forum Langage
    Réponses: 4
    Dernier message: 28/01/2009, 10h23

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