Python:继承超类__init__

时间:2011-06-30 13:51:38

标签: python inheritance constructor init

我有一个带有很多__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, ...)

...

自动调用超类__init__的最Pythonic方法是什么?

7 个答案:

答案 0 :(得分:48)

super(SubClass, self).__init__(...)

如果它有助于解决你的可变噩梦,请考虑使用* args和** kw。

答案 1 :(得分:32)

你必须明确地写它,但另一方面,如果你有很多args,你应该使用* args作为位置args和** kwargs作为关键字args。

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

答案 2 :(得分:18)

如果派生类没有实现超出基类__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__(),因此派生类中不需要进一步的工作。

答案 3 :(得分:14)

除非你在子类__init__()方法中做了一些有用的事情,否则你不必覆盖它。

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

答案 4 :(得分:4)

对于您的案例,更清晰的实现可能是在您的派生类中使用** 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

通过这种方法可以避免代码重复,但保留派生类中隐式添加的参数。

答案 5 :(得分:2)

在2.6及更低版本中从基类继承init,没有超级函数,你可以继承以下方式:

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

答案 6 :(得分:0)

添加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__ )