python钻石继承

如果子类继承自两个单独的超类,而那两个超类又继承自同一个公共基类,那么就构成了钻石继承体系。这种继承体系很像竖立的菱形,也称作菱形继承。

class Base:
    def __init__(self, value):
        self.value = value


class One(Base):
    def __init__(self, value):
        Base.__init__(self, value)
        self.value *= 2


class Two(Base):
    def __init__(self, value):
        Base.__init__(self, value)
        self.value += 3


class Ways(One, Two):
    def __init__(self, value):
        One.__init__(self, value)
        Two.__init__(self, value)

foo = Ways(5)
print(foo.value)

8

我们认为它会输出13,但结果却是8,因为在调用第二个超类时,即Two.__init__,它会再次调用Base.__init__,从而导致self.value重新变成5.

解决这个问题的方式是使用super方法,根据方法解析顺序(MRO)以标准化的流程来安排超类之间的初始化顺序,它也能够保证钻石顶部的公共基类的__init__方法之运行一次。

class Base:
    def __init__(self, value):
        self.value = value


class One(Base):
    def __init__(self, value):
        super(One, self).__init__(value)
        self.value *= 2


class Two(Base):
    def __init__(self, value):
        super(Two, self).__init__(value)
        self.value += 3


class Ways(One, Two):
    def __init__(self, value):
        super(Ways, self).__init__(value)

foo = Ways(5)
print(foo.value)

16

这是怎么回事?为何和我们设想的刚好相反。应该先运行One.__init__,然后运行Two.__init__。但实际却不一样,程序的运行会与Ways的MRO顺序保持一致。调用Ways(5)时,它会调用One.__init__,One.__init__又调用Two.__init__,Two.__init__在调用Base.__init__。到达了钻石继承的顶端,所有的初始化方法会按照与刚才那些__init__相反的顺序操作。

class Base:
    def __init__(self, value):
        self.value = value


class One(Base):
    def __init__(self, value):
        super(One, self).__init__(value * 2)


class Two(Base):
    def __init__(self, value):
        super(Two, self).__init__(value + 3)


class Ways(One, Two):
    def __init__(self, value):
        super(Ways, self).__init__(value)

foo = Ways(5)
print(foo.value)

13
这样做问题就解决了。

猜你喜欢

转载自blog.csdn.net/yangjiajia123456/article/details/80382583