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.
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.
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.
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')
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.
#!/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
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
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.
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!
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 ?
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.
Python c'est bon, mangez-en.