Python: наследовать суперкласс __init__ - PullRequest
55 голосов
/ 30 июня 2011

У меня есть базовый класс с большим количеством __init__ аргументов:

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

Все наследующие классы должны запускать __init__ метод базового класса.

Я могу написать __init__() метод в каждом из наследующих классов, который будет вызывать суперкласс __init__, но это будет серьезным дублированием кода:

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, ...)

...

Какой самый Pythonic способ автоматически назвать суперкласс __init__?

Ответы [ 7 ]

48 голосов
/ 30 июня 2011
super(SubClass, self).__init__(...)

Подумайте об использовании * args и ** kw, если это поможет решить ваш переменный кошмар.

32 голосов
/ 30 июня 2011

Вы должны написать это явно, но с другой стороны, если у вас много аргументов, вы, вероятно, должны использовать * args для позиционных аргументов и ** kwargs для ключевых слов.

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

ДругойТехника, которую вы можете использовать, заключается в минимизации кода в init , а затем в конце функции init вызовите другую пользовательскую функцию.Затем в подклассе вам просто нужно переопределить пользовательскую функцию

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
        ...
18 голосов
/ 30 июня 2011

Если производные классы не реализуют ничего, кроме того, что уже делает базовый класс __init__(), просто опустите методы __init__() производных классов - тогда базовый класс __init__() вызывается автоматически.

Если, OTOH, ваши производные классы добавляют некоторую дополнительную работу в __init__(), и вы не хотите, чтобы они явно вызывали свой базовый класс __init__(), вы можете сделать это:

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 '''

Поскольку __new__() всегда вызывается автоматически, в производных классах дальнейшая работа не требуется.

14 голосов
/ 30 июня 2011

Если вы не делаете что-то полезное в методах подкласса __init__(), вам не нужно переопределять это.

4 голосов
/ 31 марта 2018

Возможно, более ясная реализация для вашего случая использует ** kwargs в сочетании с новыми добавленными аргументами в вашем производном классе, как в:

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

С помощью этого метода вы избегаете дублирования кодано сохраните неявное добавление аргументов в вашем производном классе.

2 голосов
/ 12 января 2017

В версии 2.6 и ниже для наследования init от базового класса суперфункции нет, наследовать можно следующим образом:

class NewClass():
     def __init__():
         BaseClass.__init__(self, *args)
0 голосов
/ 29 января 2016

Добавление Pythonic-реализации.Предполагая, что вы хотите передать все атрибуты, вы можете использовать код ниже.(Можно также сохранить / удалить определенные ключи kwargs, если вы хотите подмножество).

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

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