子類繼承的初始化規(guī)則
首先需要說明關(guān)于類繼承方面的初始函數(shù)__init__() :
- 如果子類沒有定義自己的初始化函數(shù),父類的初始化函數(shù)會被默認(rèn)調(diào)用,但是需要在實例化子類的對象時傳入父類初始化函數(shù)對應(yīng)的參數(shù)
- 如果子類定義了自己的初始化函數(shù),而在子類中沒有顯式調(diào)用父類的初始化函數(shù),則父類的屬性不會被初始化,
- 如果子類定義了自己的初始化函數(shù),在子類中顯示調(diào)用父類,子類和父類的屬性都會被初始化
對于情況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)
結(jié)果為:
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)
結(jié)果顯示為:
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")
結(jié)果為:
Base create
id = 2
john 2
其中Base.__init__(self, "A") 就是樸素的子類調(diào)用父類的初始化,初始化時必須填入位置變量name 即這里的"A" ,而關(guān)鍵字變量id 可選。
super()
注意super()只能用在新式類中(當(dāng)然用python3的人不用擔(dān)心這個問題),并且在單繼承類中super()跟單純的__init__()沒什么區(qū)別,如下:
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")
項目 |
方法 |
r95Xb |
6fEaz3069 |
A0Ukw |
2005-12-07 06:41:30 |
6FBlU |
抖音怎么玩 |
mRr6R |
2005.08.20 21-38-32 |
Se19O |
4QO3M4741 |
class childB(Base):
def __init__(self):
print("childB create")
# super(childB, self).__init__('B') # super,將子類名和self傳遞進(jìn)去
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__
輸出結(jié)果如下:
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和父類沒有關(guān)聯(lián),因此執(zhí)行順序是A —> B—>—>Base,執(zhí)行過程相當(dāng)于:初始化childC()時,先會去調(diào)用childA的構(gòu)造方法中的 super(childA, self).init(), super(childA, self)返回當(dāng)前類的繼承順序中childA后的一個類childB;然后再執(zhí)行childB().init(),這樣順序執(zhí)行下去。
在多重繼承里,如果把childA()中的 super(childA, self).init() 換成Base.init(self),在執(zhí)行時,繼承childA后就會直接跳到Base類里,而略過了childB:
enter A
Base create
leave A
(<class '__main__.childC'>, <class '__main__.childA'>, <class '__main__.childB'>, <class '__main__.Base'>, <type 'object'>)
super()復(fù)雜示例
下面舉一個更復(fù)雜的例子幫助更好的理解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
|