“三人行必有我師焉!”、“不恥下問”,中國的聖人先師孔子留下的文化瑰寶傳承在生活中的每個角落。
孔子是中國古代最偉大的思想家、教育家。如果說中國有一種根本的立國精神,能夠曆久不變,能夠浸潤于全民族的生命之中,又能夠表現中華民族獨特的倫理價值的話,無疑是孔子開創的儒家思想。
這就是文化的傳承。我們Python程式設計也有這種傳承即繼承。
繼承
面向對象三大特征:封裝、繼承、多态
面向對象程式設計 (OOP) 語言的一個主要功能就是“繼承”,所謂繼承就是使現有的類無需編碼便可以擁有原有類的方法和屬性。
被繼承的類可以稱之為父類、基類、超類。繼承的類可以稱之為子類、派生類。派生和繼承是一體兩面,從父類向子類看就是派生,從子類向父類看就是繼承。子類和父類的關系可以用“is a”類表示,即子類是父類的一種,是一個更具體、更加強大的父類。python支援單繼承和多繼承。
上圖中我們把【動物】看成父類而【人】和【豬】就是它的子類。或者人類也可以有子類。
單繼承
在開始給大家介紹程式設計之前,首先給需要大家了解,在Python中所有的類預設繼承object。也就是說如果你定義一個Person類,則預設會繼承object。
繼承的格式:
class 父類名: # 預設繼承object,但是都是省略了object
......
class 子類名(父類名):
....
# 沒有繼承的時候
class Person:
def __init__(self, name):
self.name = name
self.age = 18
def eat(self):
print(self.name + "正在吃飯...")
class Student:
def __init__(self, name):
self.name = name
self.age = 18
def eat(self):
print(self.name + "正在吃飯...")
def study(self):
print('我要好好學習!')
class Programer:
def __init__(self, name):
self.name = name
self.age = 18
def eat(self):
print(self.name + "正在吃飯...")
def program(self):
print('編寫程式中...')
但是我們發現三個類中有很多相同的代碼,這時候就成了代碼備援。此時我們就需要通過繼承解決問題。
将每個類中備援的代碼提取到父類中,然後子類繼承父類的就可以了。
我們按照上面繼承的格式“改裝”代碼如下:
class Person:
def __init__(self, name):
self.name = name
self.age = 18
def eat(self):
print(self.name + "正在吃飯...")
class Student(Person):
def study(self):
print('我要好好學習!')
class Programer:
def program(self):
print('編寫程式中...')
此時代碼是不是就變得很簡練了,可以建立一個Student對象或者Programer對象,調用一下eat方法看看是否有列印。
構造方法的繼承
我們在上面的代碼基礎上,建立一個Student對象。
s = Student('大寶')
s.eat()
s.study()
但是此時我們想在學生對象建立的時候就初始化一個學生的班級,我們如何實作呢?
父類__init__調用方式:
- super(目前類名,self)._init_(實參清單)
- super()._init_(實參清單)
- 父類名._init_(self,其它參數)
class Person:
def __init__(self, name):
self.name = name
self.age = 18
def eat(self):
print(self.name + "正在吃飯...")
class Student(Person):
def __init__(self,name,clazz):
# 調用父類的構造方法(3種實作方式)
# super(Student,self).__init__(name)
# super().__init__(name)
Person.__init__(self,name)
self.clazz = clazz
def study(self):
print(f'我在{self.clazz},我要好好學習!')
s = Student('大寶','一年級3班')
print(s)
s.eat()
s.study()
print(s.age)
方法的重寫
有的時候從父類繼承的方法在子類往往不能滿足需求,則需要在自己的類中定義一個同名的方法,那這種操作我們稱作重寫。
比如父類Person中的eat方法不能滿足子類Student的需求了,此時就需要在Student中重寫此方法,代碼如下:
class Student(Person):
def __init__(self,name,clazz):
super().__init__(name)
self.clazz = clazz
def study(self):
print(f'我在{self.clazz},我要好好學習!')
# 重寫eat方法
def eat(self,food):
# 此時可以調用父類原有的方法通過關鍵字super,然後再添加自己的代碼
super().eat()
print(f'{self.name}最喜歡的食物是:{food}')
# 建立對象
s = Student('大寶','一年級3班')
s.eat()
結果:
大寶正在吃飯...
大寶最喜歡的食物是:漢堡
大家發現列印結果是重寫後的eat方法,是以大家記住一點:對象在調用的時候先判斷目前類是否存在此方法,如果存在調用自己的,不存在去父類找,如果父類都沒有則報錯。
繼承注意事項:
- 并不是所有的都可以繼承哦!私有的是繼承不了的。即父類的私有屬性和私有方法是無法繼承的。
- Python中的**super()**方法設計目的是用來解決多繼承時父類的查找問題,是以在單繼承中用不用 super 都沒關系;但是,使用 super() 是一個好的習慣。一般我們在子類中需要調用父類的方法時才會這麼用。
- super()的好處就是可以避免直接使用父類的名字.主要用于多重繼承
class A:
def m(self):
print('A')
class B:
def m(self):
print('B')
class C(A):
def m(self):
print('C')
super().m()
c = C()
c.m()
這樣做的好處就是:如果你要改變子類繼承的父類(由A改為B),你隻需要修改一行代碼(class C(A): -> class C(B))即可,而不需要在class C的大量代碼中去查找、修改基類名,另外一方面代碼的可移植性和重用性也更高。
多繼承
所謂多繼承就是一個子類可以繼承多個父類。格式:
class 父類A:
......
class 父類B:
......
class 子類名(父類A,父類B,..): # 即可以通過逗号分隔跟多個父類
....
class A:
def m(self):
print('A')
class B:
def m(self):
print('B')
class C:
def print_c(self):
print('CCC')
class D(A,B,C):
def m(self):
print('D')
super().m()
d = D()
d.m()
d.print_c()
結果:
D
A
CCC
當對象d調用m()函數的時候,為什麼?因為首先在目前類搜尋是否存在m函數,如果存在則列印結果,不存在則去父類找。那super().m()調用的時候搜尋父類的順序是什麼呢?是按照繼承時括号裡面父類的順序依次查找是否存在,是以先判斷A類是否有m函數,有則調用,沒有繼續向下查找。
當然也可以通過調用:類名.__mro__來檢視查找m的順序。
print(D.__mro__)
結果:
(<class 'main.D'>, <class 'main.A'>, <class 'main.B'>, <class 'main.C'>, <class 'object'>)
但是如果我們把代碼改成如下:
class A:
def m(self):
print('A')
class B:
def m(self):
print('B')
class C(A,B):
def print_c(self):
print('CCC')
class D:
def m(self):
print('D')
class E(C,D):
def m(self):
print(E)
super().m()
print(E.__mro__)
列印結果是什麼呢?自己敲代碼分析實作一下。