解决Python类中的钻石继承问题

时间:2017-09-13 14:18:37

标签: python python-3.x inheritance multiple-inheritance diamond-problem

考虑以下python代码:

class Parent(object):
    def __init__(self, name, serial_number):
        self.name = name
        self.serial_number = serial_number


class ChildA(Parent):
    def __init__(self, name, serial_number):
        self.name = name
        self.serial_number = serial_number
        super(ChildA, self).__init__(name = self.name, serial_number = self.serial_number)

    def speak(self):
        print("I am from Child A")


class ChildB(Parent):
    def __init__(self, name, serial_number):
        self.name = name
        self.serial_number = serial_number
        super(ChildB, self).__init__(name = self.name, serial_number = self.serial_number)

    def speak(self):
        print("I am from Child B")


class GrandChild(ChildA, ChildB):
    def __init__(self, a_name, b_name, a_serial_number, b_serial_number):
        self.a_name = a_name
        self.b_name = b_name
        self.a_serial_number = a_serial_number
        self.b_serial_number = b_serial_number
        super(GrandChild, self).__init_( something )

在GrandChild中运行super函数时,格式化__init__参数的正确方法是什么,以便ChildA和ChildB都能获得正确的参数?

另外,如何从GrandChild类中访问speak方法的两个不同版本(ChildA的版本和ChildB的版本)?

2 个答案:

答案 0 :(得分:3)

所以,当你从孙子那里打电话给super时,孩子会调用__init__方法,因为super跟随__mro__属性(父母从左到右,然后祖父母从左到右,然后是曾祖父母,...)

由于chaild的 init 也会调用super,所以所有超级调用都将被链接,调用child b' s __init__并最终调用父init。 / p>

为了实现这一点,您的界面通常需要保持一致。这就是位置参数需要表示相同的事情,并且按顺序排列。

在不是这种情况的情况下,关键字参数可能会更好。

class Parent:    
    def __init__(self, name, serial, **kwargs):
        self.name = name
        self.serial = serial

class ChildA(Parent):    
    def __init__(self, a_name, a_serial, **kwargs):
        self.a_name = a_name
        self.a_serial = a_serial
        super().__init__(**kwargs)

class ChildB(Parent):    
    def __init__(self, b_name, b_serial, **kwargs):
        self.b_name = b_name
        self.b_serial = b_serial
        super().__init__(**kwargs)


class GrandChild(ChildA, ChildB):
    def __init__(self):
        super().__init__(name = "blah", a_name = "a blah", b_name = "b blah", a_serial = 99, b_serial = 99, serial = 30)

另请注意,您的代码名称和序列号在所有类之间被重用为实例属性,而且可能不是您想要的。

答案 1 :(得分:1)

在python中,can显式调用父类(的一个)上的特定方法:

ChildA.__init__(self, a_name, a_serial)
ChildB.__init__(self, b_name, b_serial)

请注意,在以这种方式调用时,您需要明确地放置self

你也可以 - 就像你一样 - 使用super()方式,这将调用"第一个"家长。确切的顺序是动态的,但默认情况下,它将执行继承层次结构的从左到右,深度优先,预先排序scans。因此,super()来电只会在__init__上致电ChildA