2017-08-01 7 views
2

J'essaie de créer des constructeurs de méthodes classmethod pour une classe enfant, mais je ne peux pas initialiser l'instance correctement.Constructeur de classe enfant utilisant super() - obtention de la méthode unbin __init __()

J'ai lu beaucoup de blogs et de réponses sur ce site et j'ai même essayé exactement ce que d'autres personnes ont posté, mais en vain. J'espère qu'il me manque quelque chose de vraiment simple. exemple de base de ce que je suis en train:

class A(object): 
    def __init__(self, foo): 
     self.foo = foo 

class B(A): 

    @classmethod 
    def make_new(cls): 
     super(B, cls).__init__('bar') 

foobar = B.make_new() 

Je continue à obtenir l'erreur de méthode non liée:

TypeError: unbound method __init__() must be called with B instance as first argument (got str instance instead) 
+0

Je suis heureux d'avoir pris ma conseil de poser une nouvelle question après être coincé dans un nouveau point. Je savais que vous y arriveriez;), Est un plus un pour la question, désolé si je ne pouvais pas répondre à temps –

Répondre

2

La méthode __init__ est une méthode d'instance régulière, pas une méthode de classe. Il a besoin que l'instance qu'il va initialiser ait déjà été créée quand elle est appelée. Votre code actuel échoue exactement de la même manière que A.__init__("foo") échouerait (ce n'est pas la faute de super).

Je suppose que vous vouliez appeler __new__ plutôt que __init__. La méthode __new__ est la méthode "constructeur" réelle qui est responsable de la création de l'instance (généralement en déléguant l'étape de création réelle à object.__new__). Vous n'avez pas non plus besoin d'utiliser super, puisque vous n'avez pas surchargé la méthode __new__ dont vous avez hérité (de object, puisque A ne la remplace pas non plus).

Mais vous n'avez pas vraiment besoin de faire cela non plus. Vous pouvez simplement appeler l'argument cls votre classmethod été passé. L'appel d'une classe est la façon normale de construire des instances:

class B(A): 
    @classmethod 
    def make_new(cls): 
     return cls("bar") # note that you also need to `return` the instance you create! 

Si le but de la méthode de classe est d'éviter de B.__init__, vous voudrez peut-être quelque chose comme:

class B(A): 
    @classmethod 
    def make_new(cls): 
     self = cls.__new__(cls) 
     super(B, self).__init__('bar') 
     return self 
+0

Merci, cela a du sens et était ce que je pensais que le problème était, mais dans mon cas particulier (réel code sur lequel je travaille), j'ai remplacé la classe de base init dans la classe B, d'où le super. J'essaie d'utiliser ce classmethod comme un constructeur alternatif qui est toujours une instance B mais qui ne suit pas le processus d'initialisation de B. Plus précisément, il s'agit de charger l'état d'instance précédent qui a été enregistré en tant que JSON et de le reconstruire dans son objet. Cela suit un processus différent, puis la création d'un nouvel objet à partir de zéro. – iceblueorbitz

+0

Ah, alors vous voulez probablement faire 'self = cls .__ new __()' suivi de 'super (B, self) .__ init __()' (avec tous les arguments nécessaires). Si 'B' a sa propre méthode' __new__' que vous voulez contourner, vous devriez appeler 'super (B, cls) .__ new __ (cls)' au lieu de simplement 'cls .__ new__', mais cela ne devrait pas être nécessaire si vous avez seulement besoin de contourner une méthode '__init__' surchargée. – Blckknght

+0

Merci beaucoup, cela semble parfaitement logique, et semble être des informations importantes manquantes de nombreux autres messages et sujets que j'ai vus. Je comprends que '__new__' est souvent mal vu, mais fonctionne très bien dans mon cas d'avoir besoin d'une logique séparée pour recharger l'histoire à partir d'un dictionnaire JSON et reconstruire l'objet. – iceblueorbitz