4

J'ai une classe Parent. Je veux définir un __new__ pour Parent donc ça fait un peu de magie à l'instanciation (pour pourquoi, voir note de bas de page). Je souhaite également que les classes enfants héritent de cette classe et d'autres classes pour obtenir les fonctionnalités de Parent. La __new__ de retournera une instance d'une sous-classe des bases de la classe enfant et de la classe Parent.Héritage multiple Python: quel __new__ appeler?

C'est la façon de définir la classe enfant:

class Child(Parent, list): 
    pass 

Mais maintenant, je ne sais pas ce que __new__ pour appeler à l » __new__Parent. Si j'appelle object.__new__, l'exemple Child ci-dessus se plaint que list.__new__ devrait être appelé. Mais comment le Parent le sait-il? Je l'ai fait le travail il boucle à travers tous les __bases__, et appelle chaque __new__ dans un bloc try::

class Parent(object): 
    def __new__(cls, *args, **kwargs): 
     # There is a special wrapper function for instantiating instances of children 
     # classes that passes in a 'bases' argument, which is the __bases__ of the 
     # Children class. 
     bases = kwargs.get('bases') 
     if bases: 
      cls = type('name', bases + (cls,), kwargs.get('attr', {})) 
      for base in cls.__mro__: 
       if base not in (cls, MyMainType): 
        try: 
         obj = base.__new__(cls) 
         break 
        except TypeError: 
         pass 
      return obj 
     return object.__new__(cls) 

Mais cela ressemble comme un hack. Sûrement, il doit y avoir une meilleure façon de faire cela?

Merci.

  • La raison pour laquelle je veux utiliser __new__ est pour que je puisse retourner un objet d'une sous-classe qui a des attributs dynamiques (la magie __int__ attributs, etc.) affectés à la classe. Je could have done this in __init__, mais je ne serais pas en mesure de modifier self.__class__ en __init__ si la nouvelle classe a une structure interne différente, ce qui est le cas ici en raison de l'héritage multiple.
+0

J'ai eu une réponse, mais je me suis rendu compte que j'avais totalement mal compris votre question, alors je l'ai supprimé et ensuite l'ai révisé et supprimé. Je pense que la nouvelle réponse répond à votre problème et fonctionnera. J'ai fait quelques tests minimes. – Omnifarious

+0

Vous êtes distinctement dans le domaine de la programmation de métaclasses, à la fois difficile et merveilleux. La raison pour laquelle vous obtenez l'erreur avec __new__ est que les objets 'object' et builtin comme' list' et 'dict', ainsi que les objets avec' __slots__' ont des configurations de mémoire différentes. Plus de perspicacité dans ce que vous essayez d'accomplir aiderait beaucoup. Vous pouvez également utiliser un décorateur de classe ou une fonction dans l'emplacement __metaclass__. –

+0

Je ne sais pas pourquoi vous devriez modifier self .__ class__, vous ne le mentionnez pas. Et si vous avez besoin de faire de la magie compliquée comme ceci dans __new__, une solution qui est souvent beaucoup plus facile est de ne pas le faire du tout, mais d'utiliser une usine. –

Répondre

4

Je pense que cela va vous obtenir ce que vous voulez:

return super(Parent, cls).__new__(cls, *args, **kwargs) 

et vous pas besoin de l'argument mot-clé bases. À moins que je ne me trompe et que vous y mettiez exprès.

+0

Je pense que cela l'a fait. J'ai essayé cela avant, malheureusement, j'avais un autre bug dans mon code qui empêchait cela de fonctionner. La super fonction est un diable d'une balle magique. –

+1

@MTsoul, Effectivement c'est. Pour être honnête, je ne sais pas pourquoi cela a fonctionné exactement, je l'ai juste pensé. :-) – Omnifarious