web-dev-qa-db-fra.com

Python: héritez de la superclasse __init__

J'ai une classe de base avec beaucoup d'arguments __init__:

def BaseClass(object):
    def __init__(self, a, b, c, d, e, f, ...):
        self._a=a+b
        self._b=b if b else a
        ...

Toutes les classes héritées doivent exécuter la méthode __init__ De la classe de base.

Je peux écrire une méthode __init__() dans chacune des classes héritées qui appellerait la superclasse __init__, Mais ce serait une sérieuse duplication de code:

def A(BaseClass):
    def __init__(self, a, b, c, d, e, f, ...):
        super(A, self).__init__(a, b, c, d, e, f, ...)

def B(BaseClass):
    def __init__(self, a, b, c, d, e, f, ...):
        super(A, self).__init__(a, b, c, d, e, f, ...)

def C(BaseClass):
    def __init__(self, a, b, c, d, e, f, ...):
        super(A, self).__init__(a, b, c, d, e, f, ...)

...

Quelle est la façon la plus pythonique d'appeler automatiquement la superclasse __init__?

55
Adam Matan
super(SubClass, self).__init__(...)

Pensez à utiliser * args et ** kw si cela aide à résoudre votre cauchemar variable.

48
Andreas Jung

Vous devez l'écrire explicitement, mais d'un autre côté, si vous avez beaucoup d'arguments, vous devriez probablement utiliser * args pour les arguments positionnels et ** kwargs pour les arguments du mot clé.

class SubClass(BaseClass):
    def __init__(self, *args, **kwargs):
        super(SubClass, self).__init__(*args, **kwargs)
        # SubClass initialization code

Une autre technique que vous pouvez utiliser consiste à réduire le code dans init puis à la fin de la fonction init, appelez une autre fonction personnalisée. Ensuite, dans la sous-classe, il vous suffit de remplacer la fonction personnalisée

class BaseClass(object):
    def __init__(self, *args, **kwargs):
        # initialization code
        self._a = kwargs.get('a')
        ...
        # custom code for subclass to override
        self.load()

    def load():
        pass

class SubClass(BaseClass)
    def load():
        # SubClass initialization code
        ...
32
Ryan Ye

Si les classes dérivées n'implémentent rien au-delà de ce que fait déjà la classe de base __init__(), omettez simplement les méthodes des classes dérivées __init__() - la classe de base __init__() est alors appelé automatiquement.

Si, OTOH, vos classes dérivées ajoutent du travail supplémentaire dans leur __init__(), et que vous ne voulez pas qu'elles appellent explicitement leur classe de base __init__(), vous pouvez le faire:

class BaseClass(object):
    def __new__(cls, a, b, c, d, e, f, ...):
        new = object.__new__(cls)
        new._a=a+b
        new._b=b if b else a
        ...
        return new

class A(BaseClass):
    ''' no __init__() at all here '''

class B(BaseClass):
    def __init__(self, a, b, c, d, e, f, ...):
        ''' do stuff with init params specific to B objects '''

Puisque __new__() est toujours appelé automatiquement, aucun travail supplémentaire n'est requis dans les classes dérivées.

18
pillmuncher

À moins que vous ne fassiez quelque chose d'utile dans les méthodes de la sous-classe __init__(), vous n'avez pas à la remplacer.

def BaseClass(object):
    def __init__(self, a, b, c, d, e, f, ...):
        self._a=a+b
        self._b=b if b else a
        ...

def A(BaseClass):
    def some_other_method(self):
        pass

def B(BaseClass):
    pass
14
Rob Cowie

Peut-être qu'une implémentation plus claire pour votre cas utilise ** kwargs combinée avec de nouveaux arguments ajoutés dans votre classe dérivée comme dans:

class Parent:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c


class Child(Parent):
    def __init__(self, d, **kwargs):
        super(Child, self).__init__(**kwargs)
        self.d = d

Par cette méthode, vous évitez la duplication de code mais conservez l'ajout implicite d'arguments dans votre classe dérivée.

6
avielbl

Dans la version 2.6 et inférieure pour hériter init de la classe de base, il n'y a pas de super fonction, vous pouvez hériter de la manière suivante:

class NewClass():
     def __init__():
         BaseClass.__init__(self, *args)
2
Aashutosh jha

Ajout d'une implémentation Pythonic. En supposant que vous souhaitez que tous les attributs soient transmis, vous pouvez utiliser le code ci-dessous. (Peut également conserver/supprimer des clés kwargs spécifiques si vous voulez un sous-ensemble).

def A(BaseClass):
    def __init__(self, *args, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

base = BaseClass(...)
new = A( **base.__dict__ )
0
Ben