解决Python类中的菱形继承

rqdpfwrv  于 2023-05-02  发布在  Python
关注(0)|答案(3)|浏览(114)

考虑以下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的版本)?

xkftehaa

xkftehaa1#

所以,当你从孙调用super时,ChildA__init__方法将被调用,因为super遵循__mro__属性(父代从左到右,然后祖父母从左到右,然后曾祖父母,...)
由于ChildAinit也调用super,那么所有的super调用将被链接,调用子b的__init__,并最终调用父init。
要做到这一点,您的界面通常需要保持一致。也就是说,位置参数需要意味着相同的事情,并且按照顺序。
在情况并非如此的情况下,关键字参数可能会更好地工作。

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)

还要注意,在您的代码中,name和serial在所有类之间被重用为示例属性,这可能不是您想要的。

sqxo8psd

sqxo8psd2#

在python中,你可以显式地调用你的父类上的一个特定方法:

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

请注意,当以这种方式调用时,需要显式地将self放入。
您也可以像以前一样使用super()方式,它将调用“第一个”父节点。确切的顺序是动态的,但默认情况下,它将对继承层次结构进行从左到右、深度优先的预排序扫描。因此,您的super()调用将仅在ChildA上调用__init__

bzzcjhmw

bzzcjhmw3#

钻石问题在Python中不存在,因为它优先考虑首先继承的类。

class Parent:    
    def __init__(self, name, serial):
        self.name = name
        self.serial = serial
        
    def printName(self):
        print("Inside P");

class ChildA(Parent):    
    def __init__(self, a_name, a_serial):
        self.a_name = a_name
        self.a_serial = a_serial
        
    def printName(self):
        print("Inside A");

class ChildB(Parent):    
    def __init__(self, b_name, b_serial):
        self.b_name = b_name
        self.b_serial = b_serial
        
    def printName(self):
        print("Inside B");

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)
          
obj = GrandChild();
obj.printName();

输出为A内部
在上面的示例中,**GrandChild(ChildA,ChildB)**表示类GrandChild首先继承类ChildA,然后继承类ChildB。
一旦你在D中声明了printName()方法,那么输出将是在孙子中。如果你在GC类中交换了继承的子元素的位置,那么:

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

输出为B内

相关问题