Partage
  • Partager sur Facebook
  • Partager sur Twitter

Instanciation de classe en fonction de son paramètre

Sujet résolu
    9 mars 2011 à 9:36:33

    Bonjour,

    Je suis en train de me casser la tête pour essayer de modifier une classe (lors de son instanciation) en fonction d'un string qui lui est passer en paramètre.
    Cette modification consisterais a rajouter des fonctions d'une autre classe dans celle que je veux créer en fonction de son paramètre.

    Comme j'ai l'impression de ne pas être très clair je vais essayer avec un petit exemple.
    Imaginons que j'ai une classe principale :

    class principale:
       def __init__(self,str):
    
       def fonc1(self):
    
       def fonc2(self):
    



    et deux autres classes :

    class toto:
       def Ftoto1(self):
    
       def Ftoto2(self):
    
    
    class momo:
       def Fmomo1(self):
    
       def Fmomo2(self):
    



    Quand je voudrais créer une instance de 'principale', je l'appellerais, par exemple, comme ceci:

    MonInstance = principale("toto")
    


    et en faisant ainsi MonInstance possèderais les fonctions de 'principale' mais également celle de 'toto'. Et identiquement si je fais MonInstance = principale("momo") mais a la place des fonction de 'toto', j'aurais celle de 'momo'.

    Voila, j'espère que j'aurais été assez clair, et surtout que vous pourrez m'aider.

    Tcho les gens!
    • Partager sur Facebook
    • Partager sur Twitter
      9 mars 2011 à 9:49:13

      oui, c'est clair, mais faut manger la banane par l'autre bout.
      google 'python héritage'
      • Partager sur Facebook
      • Partager sur Twitter

      Python c'est bon, mangez-en. 

        9 mars 2011 à 16:26:34

        Oui je connais le principe de l'héritage, mais je voulais essayer sans ça. Car mon but c'est d'avoir a appeler qu'une seule classe lors de l'instanciation et qui pourrait me créer des classes différentes.

        J'ai vu qu'il serai (a priori) possible de le faire en utilisant des metaclasses.
        Le problème c'est que j'ai pas compris comment elles fonctionnent.
        • Partager sur Facebook
        • Partager sur Twitter
        Anonyme
          9 mars 2011 à 16:59:38

          Citation

          Oui je connais le principe de l'héritage



          non

          Citation

          J'ai vu qu'il serai (a priori) possible de le faire en utilisant des metaclasses.



          Euhhh, non! Une classe produit des instances et une métaclasse produit des classes

          Citation

          Le problème c'est que j'ai pas compris comment elles fonctionnent.



          Essai déjà de comprendre une classe

          L'héritage ne se fait pas de la façon dont tu procèdes.

          Voir un post où j'ai déjà donné un exemple.

          Maintenant je dois dire que c'est un peu flou dans ta tête et que si tu veux des précisions, faudra être plus clair
          • Partager sur Facebook
          • Partager sur Twitter
            9 mars 2011 à 17:01:14

            http://www.siteduzero.com/tutoriel-3-3 [...] n-python.html

            Selon ce que tu souhaites faire précisément, c'est peut-être la solution que tu cherches.
            • Partager sur Facebook
            • Partager sur Twitter
              9 mars 2011 à 17:46:17

              nom = raw_input("Quelle classe voulez-vous utiliser ?")
              foo = globals()[name]()
              

              C'est absolument affreux.
              • Partager sur Facebook
              • Partager sur Twitter
              yjltg.
                10 mars 2011 à 9:01:20

                Citation : Maxibolt

                http://www.siteduzero.com/tutoriel-3-3 [...] n-python.html

                Selon ce que tu souhaites faire précisément, c'est peut-être la solution que tu cherches.


                Merci Maxibolt, c'est une idée intéressante! Je vais m'y pencher dessus.


                Citation : fred1599


                Citation

                Oui je connais le principe de l'héritage


                non


                Si

                Citation : fred1599

                Euhhh, non! Une classe produit des instances et une métaclasse produit des classes


                Oui mais si on arrive a modifier le processus de creation des classes via la metaclasse il serait peut etre possible d'arriver a faire ce que je souhaite, non?
                D'où l'idée de Maxibolt qui a l'air intéressante. Si on peut combiner métaclasse et décorateur, ça pourrait peut être marcher.

                Citation : fred1599

                L'héritage ne se fait pas de la façon dont tu procèdes.


                Je le sais, et comme je l'ai dis, ce n'est pas de l'héritage que je veux faire!



                Bon je vais regarder de plus près les décorateur, mais un peu plus tard... Car là j'ai pas trop le temps.

                Voila, et merci encore pour vos réponse
                • Partager sur Facebook
                • Partager sur Twitter
                  10 mars 2011 à 11:48:40

                  Pourquoi tu ne fais pas tout simplement une factory ?

                  C'est classiquement un objet auquel tu passes un token (string, int, peut importe) et qui crée une instance de la classe voulue pour toi.

                  En Python, c'est assez bête à réaliser :

                  # -*- coding: utf-8 -*-
                  __MESCLASSES = {}
                  
                  def create(token, *args, **kwargs):
                      if token in __MESCLASSES:
                          return __MESCLASSES[token](*args, **kwargs)
                      else:
                          raise IndexError("la classe demandée n'existe pas")
                  
                  def register(cls):
                      if cls.__name__ in __MESCLASSES:
                          raise IndexError('une classe à  ce nom est déjà  enregistrée')
                      else:
                          __MESCLASSES[cls.__name__] = cls
                  
                  
                  if __name__ == '__main__':
                      class Toto(object):
                          def __init__(self, val):
                              print 'toto initialisé avec la valeur', val
                              self.val = val
                  
                      register(Toto)
                      obj = create('Toto', 42)
                  


                  Si tu tiens absolument à donner un nom à ta factory, tu peux faire comme ça:

                  # -*- coding: utf-8 -*-
                  
                  class Factory(object):
                      mesclasses = {}
                  
                      @staticmethod
                      def create(token, *args, **kwargs):
                          if token in Factory.mesclasses:
                              objet = Factory.mesclasses[token](*args, **kwargs)
                              return objet
                          else:
                              raise IndexError("la classe demandée n'existe pas")
                  
                      @staticmethod
                      def register(classe):
                          if classe.__name__ in Factory.mesclasses:
                              raise IndexError('une classe à  ce nom est déjà  enregistrée')
                          else:
                              Factory.mesclasses[classe.__name__] = classe
                  
                  
                  if __name__ == '__main__':
                      class Toto(object):
                          def __init__(self, val):
                              print 'toto initialisé avec la valeur', val
                              self.val = val
                  
                  
                      Factory.register(Toto)   # pour ajouter une classe à la Factory
                  
                      obj = Factory.create('Toto', 42) # quand tu veux instancier une classe dans le
                                                       # code
                  


                  Et enfin, si tu veux pouvoir disposer de plusieurs factories différentes (selon les types d'objets, par exemple, que tu veux stocker, pour bien ranger tout ça et rajouter de la sémantique), tu peux faire comme ceci:

                  # -*- coding: utf-8 -*-
                  
                  # Attention, cette fonction retourne une CLASSE et non un objet. 
                  def makeFactory():
                      class Factory(object):
                          mesclasses = {}
                  
                          @staticmethod
                          def create(token, *args, **kwargs):
                              if token in Factory.mesclasses:
                                  objet = Factory.mesclasses[token](*args, **kwargs)
                                  return objet
                              else:
                                  raise IndexError("la classe demandée n'existe pas")
                  
                          @staticmethod
                          def register(classe):
                              if classe.__name__ in Factory.mesclasses:
                                  raise IndexError('une classe à  ce nom est déjà  enregistrée')
                              else:
                                  Factory.mesclasses[classe.__name__] = classe
                  
                      return Factory
                  
                  
                  if __name__ == '__main__':
                      class Toto(object):
                          def __init__(self, val):
                              print 'toto initialisé avec la valeur', val
                              self.val = val
                  
                      class Tata(object):
                          def __init__(self, val):
                              print 'tata initialisé avec la valeur', val
                              self.val = val
                  
                      TotoFactory = makeFactory()
                      TataFactory = makeFactory()
                  
                      TotoFactory.register(Toto)   
                      TataFactory.register(Tata)
                  
                      obj = TotoFactory.create('Toto', 42)                                 
                      try:
                          tota = TataFactory.create('Toto', 'ça devrait planter')
                      except IndexError as e:
                          print e
                      tata = TataFactory.create('Tata', 'waouh')
                  
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Zeste de Savoir, le site qui en a dans le citron !
                  Anonyme
                    10 mars 2011 à 23:19:13

                    J'ai beau relire et relire ce post, tout me laisse penser que cela peut se faire par héritage.

                    Quand je lis ceci

                    Citation


                    et en faisant ainsi MonInstance possèderais les fonctions de 'principale' mais également celle de 'toto'. Et identiquement si je fais MonInstance = principale("momo") mais a la place des fonction de 'toto', j'aurais celle de 'momo'.



                    je suis désolé, mais pour moi ça c'est typiquement de l'héritage.

                    Et dans ce cas, je ferais un code de ce genre

                    class A(object):
                        def __init__(self, nb):
                            self.nb = nb
                        def get(self, x):
                            return self.nb + x
                    
                    
                    class B(A): # j'hérite de la classe A
                        def __init__(self, n):
                            A.__init__(self, n)
                            self.n = n
                        def _get(self, y):
                            return self.get(y) # j'utilise la méthode get de la classe A
                    
                    inst = B(12)
                    print inst._get(25) # méthode _get de la classe B
                    


                    Et quand je lis ceci

                    Citation

                    Je suis en train de me casser la tête pour essayer de modifier une classe (lors de son instanciation) en fonction d'un string qui lui est passer en paramètre.
                    Cette modification consisterais a rajouter des fonctions d'une autre classe dans celle que je veux créer en fonction de son paramètre.



                    Eh bien ça me conforte encore dans l'héritage. o_O
                    • Partager sur Facebook
                    • Partager sur Twitter
                      11 mars 2011 à 0:50:42

                      Et comment tu choisis de façon simple et propre la classe dont tu hérites ?
                      • Partager sur Facebook
                      • Partager sur Twitter
                      Anonyme
                        11 mars 2011 à 1:03:03

                        Tout simplement comme ceci

                        #!/usr/bin/python
                        # -*- coding:utf8 -*-
                        
                        class A(object):
                            def __init__(self, nb):
                                self.nb = nb
                            def get(self, x):
                                return self.nb + x
                        
                        
                        class B(A): # j'hérite de la classe A
                            def __init__(self, n):
                                A.__init__(self, n)
                                self.n = n
                            def _get(self, y):
                                return self.get(y) # j'utilise la méthode get de la classe A
                        
                        inst = B(12)
                        print inst.get(25) # méthode get de la classe A
                        


                        • Partager sur Facebook
                        • Partager sur Twitter
                          11 mars 2011 à 1:06:23

                          Tu ne choisis rien du tout là, tu hérites toujours de A.
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Anonyme
                            11 mars 2011 à 1:13:33

                            Ah ok je comprend, mais je comprend pas :-°

                            En fait ce que je ne comprend pas, c'est quel est l'intérêt de choisir la classe dont on veut hériter??? Donne moi un exemple où ceci est utile, car cela j'ai jamais vu, c'est donc de la culture pour moi :)
                            • Partager sur Facebook
                            • Partager sur Twitter
                              11 mars 2011 à 2:22:25

                              Tu poses mal le problème :)
                              La question n'est pas de savoir pourquoi il serait utile de savoir de quelle classe on veut hériter : c'est de toute façon impossible à faire à l'instanciation (du moins correctement, et même salement, je ne vois pas).
                              En fait, le PO présente son sujet de la façon suivante : il veut, en instanciant sa classe, décider de quelle autre classe elle doit posséder les méthodes et les attributs. Le premier réflexe est effectivement de convertir ça en héritage, et donc d'en déduire qu'il veut instancier une classe en précisant dynamiquement de quelle autre classe elle doit hériter. Ce n'est pas la bonne approche : en réalité, il veut définir un objet qui implémente toujours un certain comportement, plus un autre comportement choisi dynamiquement.
                              Ici, l'héritage n'est pas la solution, et effectivement tu penses avec raison que ça n'a pas d'utilité : on a souvent besoin de choisir quelles fonctionnalités donner à un objet dynamiquement, mais on le fait toujours autrement (et c'est pour ça que tu ne l'as jamais rencontré : ça n'existe pas).

                              Pour ce qui est donc du problème du PO, à savoir choisir à l'instanciation les fonctionnalités de la classe, ça peut se rencontrer dans beaucoup de cas : le tutoriel de NoHaR dont j'ai donné un lien en montre un exemple.
                              • Partager sur Facebook
                              • Partager sur Twitter
                              Anonyme
                                11 mars 2011 à 10:33:42

                                Ah ok, j'ai bien compris, je vais relire le tuto de Nohar qui à l'occasion est très bien fait.

                                Merci pour les explications.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  11 mars 2011 à 11:07:52

                                  Bonjour a tous!

                                  Tout d'abord merci de vos réponse, elles m'ont été fort utiles! J'ai pu en apprendre un peu plus sur python, il reste cependant quelque point d'ombre sur ce qui a été présenté dans le sujet, mais je ne perd pas espoir ;) .

                                  Finalement j'ai reussi a obtenir un résultat. Voici donc mon code:

                                  class Gen(object):
                                      def __new__(self, *args, **keyword):
                                          for subclass in Gen.__subclasses__():
                                              if subclass.__name__ == args[0]:
                                                  return super(self, subclass).__new__(subclass)
                                              
                                      def __init__(self,name):
                                          self.name=name
                                          
                                      def bonjour(self):
                                          print 'Bonjour!'
                                  
                                  
                                  class Salut(Gen):
                                      def salut(self):
                                          print 'Salut!'
                                  
                                  class Coucou(Gen):
                                      def coucou(self):
                                          print 'Coucou!'
                                  
                                          
                                  
                                  if __name__ == "__main__" :
                                      test = Gen("Coucou")
                                      test.coucou()
                                      test.bonjour()
                                      print ''
                                      test2 = Gen("Salut")
                                      test2.bonjour()
                                      test2.salut()
                                      test2.coucou()
                                  


                                  Et le résultat :
                                  >>> 
                                  Coucou!
                                  Bonjour!
                                  
                                  Bonjour!
                                  Salut!
                                  
                                  Traceback (most recent call last):
                                    File "D:\programme python\test.py", line 37, in <module>
                                      test2.coucou()
                                  AttributeError: 'Salut' object has no attribute 'coucou'
                                  >>>
                                  


                                  Voila, comme on peut le voir, tout fonctionne bien!

                                  Encore merci a tous, et bonne continuation
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Anonyme
                                    11 mars 2011 à 11:25:21

                                    Ben tout simplement parce-que tu appelles ta classe Salut qui hérite de Gen, donc la seule possibilité c'est appeler ta fonction salut() et bonjour()

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      11 mars 2011 à 16:40:41

                                      Argh j'avais mal compris le problème du PO.

                                      Ceci dit le dernier code présenté est tout simplement horrible. Je rejoins le post de Maxibolt. Le problème est mal posé : à quoi bon caser de l'héritage à grands coups de marteau quand on peut simplement, proprement, et à juste titre encapsuler les comportements variables, sans être obligé de commettre ce genre d'horreur qui risque de péter à la première occasion ?
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Zeste de Savoir, le site qui en a dans le citron !
                                        11 mars 2011 à 16:44:18

                                        Par contre, es-ce vraiment "pythonnique" de mettre une classe à l'intérieur d'une fonction ?
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          11 mars 2011 à 18:18:14

                                          Pourquoi ça ne le serait pas ? Comment ferais-tu un décorateur de classe sans ça, alors que les décorateurs sont tout à fait une pratique pythonique ?

                                          (note que c'est pas du tout ce dont je parle dans mon précédent post)




                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Zeste de Savoir, le site qui en a dans le citron !

                                          Instanciation de classe en fonction de son paramètre

                                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                          • Editeur
                                          • Markdown