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 de classe


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut factory de classe
    Salut à tous

    J'ai une classe dont je veux qu'une méthode soit un input provenant de l'utilisateur. Cette méthode ayant peut être éventuellement besoin de définir des éléments garder en mémoire d'un appel sur l'autre, il me parait donc aussi nécessaire d'offrir à l'utilisateur un moyen de spécifier ces éléments.

    Voici un exemple avec la classe UneClasse, je vous ai mis un commentaire au bout des lignes pour lesquelles je souhaite laisser l'utilisateur libre de les définir.
    La classe Pop, ne sert que de support pour l'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
    class Pop():
        def __init__(self, a):
            self.a=a
     
    pop = Pop(10000)
     
    class RecruiterBase():
        def __init__(self, params=None):
            self.params = params
            self.r = random.Random(0)   #### Want to be user input
            self.historic = []          #### Want to be user input
     
        def GetNumberOfRecruitment(self, pop):
            res = pop.a + self.params['range']*self.r.random()   #### Want to be user input     
            self.historic.append(res)                               #### Want to be user input
            return res
     
    r_base = RecruiterBase({'range':10})
    print( "Reference:", r_base.GetNumberOfRecruitment(pop) )
    De là, je voudrais maintenant pouvoir definir ma classe à partir de cet input utilisateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def f(uneclasse, pop):
        res = pop.a + uneclasse.params['range']*uneclasse.r.random()        
        uneclasse.historic.append(res)
        return res     
     
    def f_init(uneclasse):
        uneclasse.r = random.Random(0)
        uneclasse.historic = []
    J'ai essayé 2 trucs, qui fonctionnent :
    1) Une classe qui définit sa méthode Foo dynamiquement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class UneClasse():
        def __init__(self, foo_fct=None, params=None, f_init=None):
            self.params = params
            self.Foo = partial( foo_fct, self )
            if foo_fct is None : self.Foo = lambda pop : 0
            if f_init : f_init(self)
     
    r1 = UneClasse(f, {'range':10}, f_init )
    print( "Option1  :", r1.Foo(pop) )
    2)Une factory :
    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
    def UneClasseFactory(foo_fct=None, f_init=None):
        class UneClasse():
            def __init__(self, params=None):
                self.params = params
                if f_init : f_init(self)
     
            if foo_fct :
                def Foo(self, pop):
                    return foo_fct( self, pop)
            else :
                def Foo(self, pop):
                    return 0
     
        return UneClasse
     
    r2 = UneClasseFactory(f, f_init )({'range':10})
    print("Option2  :", r2.Foo(pop) )
    Et là j'aurais besoin de vos commentaires/avis. Car je n'arrive pas à me décider entre ces 2 options (il y en a d'autres encore ceci dit). J'ai l'impression que la 1ere est beaucoup moins propre, bien que plus simple à utiliser et ayant un code plus concis.

    Merci pour vos retours

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

    Citation Envoyé par lg_53 Voir le message
    Et là j'aurais besoin de vos commentaires/avis. Car je n'arrive pas à me décider entre ces 2 options (il y en a d'autres encore ceci dit). J'ai l'impression que la 1ere est beaucoup moins propre, bien que plus simple à utiliser et ayant un code plus concis.
    Si vous voulez être un peu rigoureux écrire:
    Citation Envoyé par lg_53 Voir le message
    J'ai une classe dont je veux qu'une méthode soit un input provenant de l'utilisateur. Cette méthode ayant peut être éventuellement besoin de définir des éléments garder en mémoire d'un appel sur l'autre, il me parait donc aussi nécessaire d'offrir à l'utilisateur un moyen de spécifier ces éléments.
    suggère 2 classes: la classe de départ et celle fournie par l'utilisateur (qu'on appellera A et B).

    Car une méthode qui a une mémoire (donc un état) est un objet à part entière. C'est un objet qui devra s'interfacer avec l'autre classe.... et à partir de là, il faut qu'il y ait une base (qui fonctionne) pouvant être s/classée par l'utilisateur (qui éventuellement définira/surchargera une des méthodes).

    A défaut, on va demander à A (ou à B) de s'interfacer avec un B (ou un A) dont on ne connaît pas les spécifications (ou on compte sur l'utilisateur pour aller lire les sources pour savoir ce qu'il peut faire pour utiliser çà...).

    Cela posé, s'il faut instancier un B (ou une s/classe de B) pour fabriquer une instance de A, çà se fait simplement dans le constructeur du A.

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

  3. #3
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    Bonjour,
    Citation Envoyé par lg_53 Voir le message
    De là, je voudrais maintenant pouvoir definir ma classe à partir de cet input utilisateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def f(uneclasse, pop):
        res = pop.a + uneclasse.params['range']*uneclasse.r.random()        
        uneclasse.historic.append(res)
        return res     
     
    def f_init(uneclasse):
        uneclasse.r = random.Random(0)
        uneclasse.historic = []
    Je pense que, à la place de uneclasse, il faudrait plutôt écrire unobjet, mais ce n'est pas ce qui m'embête le plus.
    Dans ton exemple, ces deux fonctions f et f_init contiennent déjà la quasi-totalité du code de RecruiterBase. La seule ligne de code en moins est self.params = params.
    Du coup, je ne comprends pas l'intérêt que l'utilisateur crée des fonctions f et f_init qu'il donne entrée à UneClasse ou à UneClasseFactory au lieu que l'utilisateur ne code directement lui-même la classe RecruiterBase sans passer par UneClasse ou UneClasseFactory.

  4. #4
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    Bonjour,

    Je pense que, à la place de uneclasse, il faudrait plutôt écrire unobjet, mais ce n'est pas ce qui m'embête le plus.
    Certes, j'ai reformulé mon problème un peu vite. Après ce n'est qu'un nom, ça ne change pas le problème, mais en toute rigueur tu as raison de le souligner .

    Citation Envoyé par Pyramidev Voir le message
    Dans ton exemple, ces deux fonctions f et f_init contiennent déjà la quasi-totalité du code de RecruiterBase. La seule ligne de code en moins est self.params = params.
    Du coup, je ne comprends pas l'intérêt que l'utilisateur crée des fonctions f et f_init qu'il donne entrée à UneClasse ou à UneClasseFactory au lieu que l'utilisateur ne code directement lui-même la classe RecruiterBase sans passer par UneClasse ou UneClasseFactory.
    Là j'ai réduit mon problème à l'extrême mais en fait self.params = params est loin d'être le seul bout de code que l'utilisateur n'a pas à écrire.

    Pour l'option que tu proposes wiztricks, c'est laisser l'utilisateur surcharger la classe de base. J'avais écartée cette option car ça me parait, côté utilisateur, plus compliqué que de simplement écrire 2 fonctions dont le prototype est fixé. Je vais reconsidéré l'option pour voir.

    L'idée derrière aussi c'est que le code de f et de f_init soit contenu dans un fichier d'input. Ce fichier d'input peut être vu comme un fichier de configuration. Donc j'aimerais bien notamment que ce fichier ne soit pas un script complet avec en plus une dépendance (un import vers la classe de base).

  5. #5
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    Citation Envoyé par lg_53 Voir le message
    Là j'ai réduit mon problème à l'extrême mais en fait self.params = params est loin d'être le seul bout de code que l'utilisateur n'a pas à écrire.
    Citation Envoyé par lg_53 Voir le message
    L'idée derrière aussi c'est que le code de f et de f_init soit contenu dans un fichier d'input. Ce fichier d'input peut être vu comme un fichier de configuration. Donc j'aimerais bien notamment que ce fichier ne soit pas un script complet avec en plus une dépendance (un import vers la classe de base).
    Du coup, je ne connais pas assez le contexte pour savoir quelle est la meilleure solution.

    Une troisième possibilité est de définir, dans le fichier de configuration, une classe sous cette forme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class ClassInInputFile:
     
        def __init__(self):
            self.r = random.Random(0)
            self.historic = []
     
        def f(self, pop, params):
            res = pop.a + params["range"] * self.r.random()
            self.historic.append(res)
            return res
    Dans le code appelant, on aurait alors :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class UneClasse():
     
        def __init__(self, instance_of_class_in_input_file, params=None):
            self.obj = instance_of_class_in_input_file
            self.params = params
     
        def Foo(self, pop):
            return self.obj.f(pop, self.params)
    Un avantage de cette solution est de pouvoir définir des variables membres privées dans la classe ClassInInputFile. Par exemple, si le vrai code de UneClasse n'utilise pas directement self.obj.r et self.obj.historic alors, dans la classe ClassInInputFile, on peut remplacer les attributs publics r et historic par des attributs privés __r et __historic.

Discussions similaires

  1. object factory et classes templates
    Par [Hugo] dans le forum C++
    Réponses: 11
    Dernier message: 03/01/2012, 17h33
  2. [GOF] [Factory et Builder] Comment finir l'utilisation de ces classes ?
    Par dymezac dans le forum Design Patterns
    Réponses: 2
    Dernier message: 30/03/2007, 09h39
  3. Classe + design pattern factory
    Par Rodrigue dans le forum C++
    Réponses: 8
    Dernier message: 07/11/2006, 14h42

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