about 3 years ago

Initialize Parent Classes with super

不使用 super() 在多重繼承時可能會造成意想不到的問題,下面的程式造成所謂的 diamond inheritance, foo.value 的值是 7 ,而不是 27。因為 PlusTwo.__init__(self, value) 將值重設為 5 了。

class MyBaseClass(object):
    def __init__(self, value):
        self.value = value

class TimesFive(MyBaseClass):
    def __init__(self, value):
        MyBaseClass.__init__(self, value)
        self.value *= 5

class PlusTwo(MyBaseClass):
    def __init__(self, value):
        MyBaseClass.__init__(self, value)
        self.value += 2

class ThisWay(TimesFive, PlusTwo):
    def __init__(self, value):
        TimesFive.__init__(self, value)
        PlusTwo.__init__(self, value)

foo = ThisWay(5)
print('Should be (5 * 5) + 2 = 27 but is', foo.value)

使用 super() 可以正確得到 27

# Python 2

class MyBaseClass(object):
    def __init__(self, value):
        self.value = value

class TimesFiveCorrect(MyBaseClass):
    def __init__(self, value):
        super(TimesFiveCorrect, self).__init__(value)
        self.value *= 5

class PlusTwoCorrect(MyBaseClass):
    def __init__(self, value):
        super(PlusTwoCorrect, self).__init__(value)
        self.value += 2

class GoodWay(PlusTwoCorrect, TimesFiveCorrect):
    def __init__(self, value):
        super(GoodWay, self).__init__(value)

注意 MRO 的執行順序是 DFS ,也就是說 MyBaseClass.__init__() 執行完返回接著是 TimesFiveCorrect.__init__() -> PlusTwoCorrect.__init__()

# Python 2

print GoodWay.mro()
[<class '__main__.GoodWay'>, <class '__main__.PlusTwoCorrect'>, <class '__main__.TimesFiveCorrect'>, <class '__main__.MyBaseClass'>, <type 'object'>]

Python 3 簡化了 super() 的使用方式

class Implicit(MyBaseClass):
    def __init__(self, value):
        super().__init__(value * 2)
← Effective Python 心得筆記: Item 24 Effective Python 心得筆記: Item 26 →
 
comments powered by Disqus