2017-02-10 5 views
1

Actuellement, j'ai un @classmethod qui retourne la bonne classe étant donné une variable. Il ressemble à:Avoir une classe pour initialiser un objet d'une classe différente

class Parent(): 
    @classmethod 
    def GetInstance(cls, variable): 
    if variable == 'foo': 
     return Child() 


class Child(Parent): 
    def Something(self): 
    pass 

instance = Parent.GetInstance('foo') 
result = instance.Something() 

Je préfère ne pas définir et utiliser GetInstance. Au lieu de cela, je voudrais que le Main() N'être:

instance = Parent('foo') 
result = instance.Something() 

Tout en gardant tous les avantages de la structure ci-dessus. Je veux que la classe Parent() renvoie un objet de la classe Child() lorsqu'il est appelé, sans avoir besoin d'utiliser une méthode. __init__ ne semble malheureusement pas aider, car il ne peut rien retourner. Des idées?

+0

Vous pouvez utiliser '__new__', mais dans de nombreux cas, il vaut mieux simplement écrire une fonction usine. – BrenBarn

+0

Oui, le modèle de classe de Python ne supporte pas facilement cela. Je ne peux pas penser à un moyen, parce que, comme vous l'avez découvert, «initit» n'aime pas «retourner» les choses. Utilisez juste le modèle d'usine ... ceci est bien connu. –

+0

@BrenBarn Oui, je suppose que vous pouvez utiliser '__new__'. Ce serait une solution totalement sur-ingénierie à un non-problème. Ce serait totalement surprenant pour quiconque utilise votre «classe». –

Répondre

-1

Ajouter une liste des enfants [] dans votre classe parent:

class Parent(): 
    def __init__(self): 
     children = list() 

De cette façon, vous pouvez créer un objet enfant(), puis l'ajouter en faisant:

child - Child() # create new child obj 
parent.children.append(child) 

Ensuite, il devrait être simple pour obtenir un enfant de la liste des enfants que vous voulez en utilisant une boucle, etc.

+0

L'objectif n'est pas de créer une liste d'enfants, mais de passer un paramètre et dans le cas où le paramètre de '' foo'', construire un enfant à la place. –

+0

@WillemVanOnsem pourquoi ne publiez-vous pas juste une réponse? – codeglove26

+0

Je l'ai fait jusqu'à ce que je me suis rendu compte que la réponse n'était pas si triviale. Une fois que vous avez les droits d'administrateur, vous pouvez même voir cette réponse;). –

0

Remplacez simplement 'nouvelle' méthode spéciale. C'est la méthode 'nouvelle' qui est chargée d'appeler la création d'une instance, d'allouer de la mémoire et de l'initialiser en appelant 'init'. Pour être précis

nouvelle est méthode de classe statique, alors que initialisation est méthode d'instance. nouveau doit créer l'instance en premier, donc init peut l'initialiser. Notez que init prend self comme paramètre. Jusqu'à ce que vous créez une instance, il n'y a pas de soi.

+0

Il me semble que le problème est que vous recevrez le rappel: le '__new__' appelle 'Child()', l'enfant appelle le '__new__' de l'enfant qui appellera le' '__new__' du parent '' et ainsi vous recevrez l'appel deux fois. –

0

EDIT Ok, je suis revenu et je l'ai corrigé. Totalement hackey et très fragile. J'espère que vous ne voulez pas continuer à étendre cela. Je mets ceci ici comme illustratif de pourquoi c'est une mauvaise idée.

Voici une esquisse de la façon dont pourrait accomplir ceci. Mais s'il vous plaît, il suffit d'utiliser une méthode d'usine.

>>> class Parent(object): 
...  def __new__(typ, *args, **kwargs): 
...   if args and args[0] == 'foo': 
...    return Child() 
...   else: 
...    return super(Parent, typ).__new__(typ) 
... 
>>> class Child(Parent): 
...  __new__ = object.__new__ 
... 
>>> a = Parent('foo') 
>>> a 
<__main__.Child object at 0x1023275f8> 
>>> p = Parent() 
>>> p 
<__main__.Parent object at 0x1023275c0> 
>>> 
+0

Ils souhaitent avoir 'Child' comme un enfant de' Parent', qui est d'où je suppose que les difficultés avec '__new__' viennent. –

+0

@KevinMGranger merde, mon erreur. Ouais, ça devient salissant rapidement. Donne-moi une seconde ... –

+0

@KevinMGranger Ok, j'ai un squelette qui marche maintenant, fragile comme un enfer. –