繼承介紹
繼承指的是類與類之間的關(guān)系,是一種什么是什么的關(guān)系哮洽,功能之一就是用來解決代碼重用問題打却。
繼承是一種創(chuàng)建新類的方式杉适,在python中,新建的類可以繼承一個或多個父類柳击,父類又可稱為基類或超類猿推,新建的類稱為派生類或子類
python 中分為單繼承和多繼承
python中類可以繼承多個類.
class ParentClass1: #定義父類
pass
class ParentClass2: #定義父類
pass
class SubClass1(ParentClass1): #單繼承,基類是ParentClass1捌肴,派生類是SubClass
pass
class SubClass2(ParentClass1,ParentClass2): # python支持多繼承蹬叭,用逗號分隔開多個繼承的類
pass
查看繼承的類:
res=SubClass2.__bases__
print(res)
#__base__只查看從左到右繼承的第一個子類,__bases__則是查看所有繼承的父類
輸出:
(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
經(jīng)典類和新式類
1.只有在python2中才分新式類和經(jīng)典類状知,python3中統(tǒng)一都是新式類
2.在python2中秽五,沒有顯式的繼承object類的類,以及該類的子類饥悴,都是經(jīng)典類
3.在python2中筝蚕,顯式地聲明繼承object的類,以及該類的子類铺坞,都是新式類
3.在python3中起宽,無論是否繼承object,都默認(rèn)繼承object济榨,即python3中所有類均為新式類
提示:如果沒有指定基類坯沪,python的類會默認(rèn)繼承object類,object是所有python類的基類擒滑,它提供了一些常見方法(如str)的實(shí)現(xiàn)腐晾。
res=ParentClass1.__bases__
print(res)
# 輸出:
(<class 'object'>,)
在開發(fā)程序的過程中,如果我們定義了一個類A丐一,然后又想新建立另外一個類B藻糖,但是類B的大部分內(nèi)容與類A的相同時
我們不可能從頭開始寫一個類B,這就用到了類的繼承的概念库车。
通過繼承的方式新建類B巨柒,讓B繼承A,B會‘遺傳’A的所有屬性(數(shù)據(jù)屬性和函數(shù)屬性)柠衍,實(shí)現(xiàn)代碼重用
在不依賴?yán)^承屬性的情況下,子類在調(diào)用父類的屬性時,可以直接通過函數(shù)調(diào)用的方式調(diào)用父類的屬性:
class ParentClass: #定義父類
def __init__(self,name,age):
self.name=name
self.age=age
class SubClass(ParentClass):
def __init__(self,name,age,hobby,title):
ParentClass.__init__(self,name,age) # 直接以函數(shù)的方式調(diào)用父類的屬性
self.hobby=hobby
self.title=title
obj=SubClass('tom',22,'reading','Student')
print(obj.__dict__)
注意:類的屬性引用洋满,會先從實(shí)例中找,然后去類中找,然后再去父類中找...直到最頂級的父類珍坊。
組合
組合指的是牺勾,在一個類中以另外一個類的對象作為數(shù)據(jù)屬性,稱為類的組合
組合與繼承都是有效地利用已有類的資源的重要方式阵漏。但是二者的概念和使用場景皆不同:
1.繼承的方式
通過繼承建立了派生類與基類之間的關(guān)系驻民,它是一種'是'的關(guān)系翻具,比如白馬是馬,人是動物回还。
當(dāng)類之間有很多相同的功能裆泳,提取這些共同的功能做成基類,用繼承比較好懦趋,比如老師是人,學(xué)生是人
2.組合的方式
用組合的方式建立了類與組合的類之間的關(guān)系疹味,它是一種‘有’的關(guān)系,比如教授有生日仅叫,教授教python和linux課程,教授有學(xué)生s1糙捺、s2诫咱、s3...
示例:
# coding=utf-8
class People:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
class Course:
def __init__(self,name,period,price):
self.name=name
self.period=period
self.price=price
def tell_info(self):
print('%s %s %s' %(self.name,self.period,self.price))
class Teacher(People):
def __init__(self,name,age,sex,job_title):
People.__init__(self,name,age,sex)
self.job_title=job_title
self.course=[]
self.students=[]
class Student(People):
def __init__(self,name,age,sex):
People.__init__(self,name,age,sex)
self.course=[]
egon=Teacher('egon',18,'male','advance')
s1=Student('bob',18,'female')
python=Course('python','3mons',3000.0)
linux=Course('linux','3mons',3000.0)
#為老師egon和學(xué)生s1添加課程
egon.course.append(python)
egon.course.append(linux)
s1.course.append(python)
#為老師egon添加學(xué)生s1
egon.students.append(s1)
#使用
for obj in egon.course:
obj.tell_info()
print(egon.__dict__)
輸出結(jié)果:
python 3mons 3000.0
linux 3mons 3000.0
{'name': 'egon', 'age': 18, 'sex': 'male', 'job_title': 'advance', 'course': [<__main__.Course object at 0x000000410AF46CC0>, <__main__.Course object at 0x000000410AF46CF8>], 'students': [<__main__.Student object at 0x000000410AF46C88>]}
繼承實(shí)現(xiàn)的原理
1、繼承順序
* python 類可以繼承多個類洪灯,java和C#中則只能繼承一個類
* Python 的類如果繼承了多個類坎缭,那么其查找父類的順序有兩種:深度優(yōu)先
和廣度優(yōu)先
* 當(dāng)類是經(jīng)典類時,多繼承情況下签钩,會按照深度優(yōu)先的方式查找
* 當(dāng)類是新式類時掏呼,多繼承情況下,會按照廣度優(yōu)先的方式查找
推薦使用新式類铅檩,如果當(dāng)前類或者父類繼承了object類憎夷,那么該類便是一個新式類,否則便是經(jīng)典類昧旨。(經(jīng)典類之存在于python2中)
2拾给、繼承原理(python如何實(shí)現(xiàn)的繼承)
python實(shí)現(xiàn)繼承的原理是: 對于定義的每一個類,python都會計(jì)算出一個方法解析順序(MRO)列表兔沃,這個MRO列表就是一個簡單的所有基類的線性順序表蒋得。
class A:
pass
class B(A):
pass
class C:
pass
class D(C,B):
pass
obj=D()
print(D.mro())
# 輸出列表:
[<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
為了實(shí)現(xiàn)繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。
而這個MRO列表的構(gòu)造是通過一個C3線性化算法來實(shí)現(xiàn)的乒疏。我們不去深究這個算法的數(shù)學(xué)原理,它實(shí)際上就是合并所有父類的MRO列表并遵循如下三條準(zhǔn)則:
- 子類會先于父類被檢查
- 多個父類會根據(jù)它們在列表中的順序被檢查
- 如果對下一個類存在兩個合法的選擇,選擇第一個父類
子類中調(diào)用父類的方法
1额衙、通過指定父類方法名的方式去調(diào)用。(不利用繼承的屬性)
2怕吴、通過使用super()
class Subway(Vehicle): #地鐵
def __init__(self,name,speed,load,power,line):
#super(Subway,self) 就相當(dāng)于實(shí)例本身, 在python3中super()等同于super(Subway,self)
super().__init__(name,speed,load,power) # 調(diào)用父類的init方法.
self.line=line
注意:
當(dāng)你使用super()函數(shù)時,Python會在MRO列表上繼續(xù)搜索下一個類入偷。只要每個重定義的方法統(tǒng)一使用super()并只調(diào)用它一次,那么控制流最終會遍歷完整個MRO列表,每個方法也只會被調(diào)用一次(注意注意注意:使用super調(diào)用的所有屬性,都是從MRO列表當(dāng)前的位置往后找械哟,千萬不要通過看代碼去找繼承關(guān)系疏之,一定要看MRO列表)
綁定方法與非綁定方法
類中的函數(shù)可以定義為兩大類,一種是綁定方法暇咆,另一種是非綁定方法锋爪。
1丙曙、綁定方法:綁定給誰,誰來調(diào)用就自動將它本身當(dāng)作第一個參數(shù)傳入:
- 綁定到類的方法:用classmethod裝飾器裝飾的方法其骄。
為類量身定制亏镰,自動將類當(dāng)作第一個參數(shù)傳入。(其實(shí)對象也可調(diào)用拯爽,但仍將類當(dāng)作第一個參數(shù)傳入)
- 綁定到對象的方法:沒有被任何裝飾器裝飾的方法索抓。、
為對象量身定制對象毯炮,自動將對象當(dāng)作第一個參數(shù)傳入(屬于類的函數(shù)逼肯,類可以調(diào)用,但是必須按照函數(shù)的規(guī)則來桃煎,沒有自動傳值那么一說)
2篮幢、 非綁定方法:用staticmethod裝飾器裝飾的方法
- 不與類或?qū)ο蠼壎ǎ惡蛯ο蠖伎梢哉{(diào)用为迈,但是沒有自動傳值那么一說三椿。就是一個普通工具而已。在非綁定方法中不需要(不會自動傳值)傳入對象和類葫辐,只是執(zhí)行函數(shù)功能搜锰。
> 注意:與綁定到對象方法區(qū)分開,在類中直接定義的函數(shù)耿战,沒有被任何裝飾器裝飾的纽乱,都是綁定到對象的方法,可不是普通函數(shù)昆箕,對象調(diào)用該方法會自動傳值鸦列,而staticmethod裝飾的方法,不管誰來調(diào)用鹏倘,都沒有自動傳值一說薯嗤。