python類中super()與__init__()


 

子類繼承的初始化規則

首先需要說明關於類繼承方面的初始函數__init__()

  • 如果子類沒有定義自己的初始化函數,父類的初始化函數會被默認調用,但是需要在實例化子類的對象時傳入父類初始化函數對應的參數
  • 如果子類定義了自己的初始化函數,而在子類中沒有顯式調用父類的初始化函數,則父類的屬性不會被初始化,
  • 如果子類定義了自己的初始化函數,在子類中顯示調用父類,子類和父類的屬性都會被初始化

對於情況1,如下:

class Base:
    def __init__(self, name, id = 2):
        self.name = name
        self.id = id
        print("Base create")
        print("id = ", self.id)
    def func(self):
        print("base fun")
class childA(Base):
    # def __init__(self):
    # print("childA create")
        # Base.__init__(self, "A") # 父類名硬編碼到子類中
    def funA(self):
        print("funA")

A = childA('john',id=2) # 必須手動傳入,否則A還是不會有name和id對象
print(A.name, A.id)

結果為:

Base create
id =  2
john 2

對於情況2,如下:

class Base:
    def __init__(self, name, id = 2):
        self.name = name
        self.id = id
        print("Base create")
        print("id = ", self.id)
    def func(self):
        print("base fun")
class childA(Base):
    def __init__(self):
        print("childA create")
        # Base.__init__(self, "A") # 父類名硬編碼到子類中
    def funA(self):
        print("funA")

A = childA()
print(A.name, A.id)

結果顯示為:

AttributeError: 'childA' object has no attribute 'name'

對於情況3,如下:

class Base:
    def __init__(self, name, id = 2):
        self.name = name
        self.id = id
        print("Base create")
        print("id = ", self.id)
    def func(self):
        print("base fun")
class childA(Base):
    def __init__(self):
        print("childA create")
        Base.__init__(self, "A")        # 父類名硬編碼到子類中
    def funA(self):
        print("funA")

結果為:

Base create
id =  2
john 2

其中Base.__init__(self, "A")就是朴素的子類調用父類的初始化,初始化時必須填入位置變量name即這里的"A",而關鍵字變量id可選。

super()

注意super()只能用在新式類中(當然用python3的人不用擔心這個問題),並且在單繼承類中super()跟單純的__init__()沒什么區別,如下:

class Base:
    def __init__(self, name, id = 2):
        self.name = name
        self.id = id
        print("Base create")
        print("id = ", self.id)
    def func(self):
        print("base fun")
        
class childA(Base):
    def __init__(self):
        print("childA create")
        Base.__init__(self, "A")        # 父類名硬編碼到子類中
    def funA(self):
        print("funA")
        
class childB(Base):
    def __init__(self):
        print("childB create")
        # super(childB, self).__init__('B') # super,將子類名和self傳遞進去
        super().__init__('B',id=3) # python3可以直接簡化成這個形式
        self.id = 3

另外需要注意的是super不是父類,而是繼承順序的下一個類,如下是多類繼承的情況:

class Base(object):
    def __init__(self):
        print 'Base create'

class childA(Base):
    def __init__(self):
        print 'enter A '
        # Base.__init__(self)
        super(childA, self).__init__()
        print 'leave A'


class childB(Base):
    def __init__(self):
        print 'enter B '
        # Base.__init__(self)
        super(childB, self).__init__()
        print 'leave B'

class childC(childA, childB):
    pass

c = childC()
print c.__class__.__mro__

輸出結果如下:

enter A 
enter B 
Base create
leave B
leave A
(<class '__main__.childC'>, <class '__main__.childA'>, <class '__main__.childB'>, <class '__main__.Base'>, <type 'object'>)

supder和父類沒有關聯,因此執行順序是A —> B—>—>Base,執行過程相當於:初始化childC()時,先會去調用childA的構造方法中的 super(childA, self).init(), super(childA, self)返回當前類的繼承順序中childA后的一個類childB;然后再執行childB().init(),這樣順序執行下去。

在多重繼承里,如果把childA()中的 super(childA, self).init() 換成Base.init(self),在執行時,繼承childA后就會直接跳到Base類里,而略過了childB:

enter A 
Base create
leave A
(<class '__main__.childC'>, <class '__main__.childA'>, <class '__main__.childB'>, <class '__main__.Base'>, <type 'object'>)

super()復雜示例

下面舉一個更復雜的例子幫助更好的理解super():

class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

    def perimeter(self):
        return 2 * self.length + 2 * self.width

class Square(Rectangle):
    def __init__(self, length):
        super(Square, self).__init__(length, length)
class Triangle:
    def __init__(self, base, height):
        self.base = base
        self.height = height

    def area(self):
        return 0.5 * self.base * self.height

class RightPyramid(Triangle, Square):
    def __init__(self, base, slant_height):
        self.base = base
        self.slant_height = slant_height

    def area(self):
        base_area = super().area()
        perimeter = super().perimeter()
        return 0.5 * perimeter * self.slant_height + base_area


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM