一、繼承介紹
1、什么是繼承
繼承是一種新建類的方式,新建的類稱之為子類,
被繼承的類稱之為父類、基類、超類
python支持多繼承,用逗號分隔開多個繼承的類
查看繼承:派生類名.__bases__ #__base__只查看從左到右繼承的第一個父類,__bases__則是查看所有繼承的父類
2、為何要繼承
子類會遺傳父類的屬性,所以繼承是用來解決類與類之間代碼冗余問題
PS:類是為了解決物件與物件之間代碼冗余問題
3、如何實作繼承
ps:單繼承能更好的反應什么是什么的關系
# 繼承案列: class OldboyPeople: school = "oldboy" class Student(OldboyPeople): def __init__(self,name,age,gender,stud_id,course): self.name = name self.age = age self.gender = gender self.stu_id = stud_id self.course = course def choose(self): print('%s 正在選課' %self.name) class Teacher(OldboyPeople): def __init__(self,name,age,gender,salary,level): self.name = name self.age = age self.gender = gender self.salary = salary self.level = level def score(self,stu,num): stu.num = num stu1=Student("艾利克斯",73,'male',1001,"python全堆疊開放") tea1=Teacher("egon",18,'male',2000,10) print(stu1.school)
二、在子類派生的新方法中重用父類的功能
方式一:指名道姓地呼叫某一個類的函式
特點:不依賴于繼承關系
class OldboyPeople: school = "oldboy" # 空物件,"艾利克斯",73,'male' def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def f1(self): print('1111111') class Student(OldboyPeople): # 空物件,"艾利克斯",73,'male',1001,"python全堆疊開放" def __init__(self,name,age,gender,stu_id,course): OldboyPeople.__init__(self,name,age,gender) # OldboyPeople.__init__(空物件,"艾利克斯",73,'male') self.stu_id = stu_id self.course = course def choose(self): print('%s 正在選課' %self.name) def f1(self): OldboyPeople.f1(self) print("22222") class Teacher(OldboyPeople): def score(self,stu,num): stu.num = num stu1=Student("艾利克斯",73,'male',1001,"python全堆疊開放") # tea1=Teacher("egon",18,'male',2000,10) stu1.f1()
方式二:呼叫super(自己的類名,self)會回傳一個特殊的物件,super(自己的類名,self).屬性,會參照屬性查找發起的那個類的mro串列去它父類中查找屬性
特點:嚴格依賴于繼承關系
#1 class OldboyPeople: school = "oldboy" # 空物件,"艾利克斯",73,'male' def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def f1(self): print('1111111') class Student(OldboyPeople): def __init__(self,name,age,gender,stu_id,course): # OldboyPeople.__init__(self,name,age,gender) # OldboyPeople.__init__(空物件,"艾利克斯",73,'male') super(Student,self).__init__(name,age,gender) self.stu_id = stu_id self.course = course def choose(self): print('%s 正在選課' %self.name) def f1(self): # OldboyPeople.f1(self) # super().f1() print("22222") # print(Student.mro()) stu1=Student("艾利克斯",73,'male',1001,"python全堆疊開放") # print(stu1.__dict__) stu1.f1() #2: class A: def test(self): super().test() class B: def test(self): print('from B') class C(A,B): pass c=C() print(C.mro()) c.test() obj=A() obj.test() #3: class A: def test(self): print('A---->test') super().aaa() class B: def test(self): print('B---->test') def aaa(self): print('B---->aaa') class C(A,B): def aaa(self): print('C----->aaa') c=C() print(C.mro()) c.test()
三、屬性查找
# 例1:有了繼承關系,物件在查找屬性時,先從物件自己的__dict__中找,如果沒有則去子類中找,然后再去父類中找 class Foo: def f2(self): print("Foo.f2") def f1(self): print('Foo.f1') self.f2() # obj.f2() class Bar(Foo): def f2(self): print("Bar.f2") obj = Bar() obj.f1()
# 例2:父類如果不想讓子類覆寫自己的方法,可以在方法名前加前綴__ class Foo: def __f2(self): # _Foo__f2 print("Foo.f2") def f1(self): print('Foo.f1') self.__f2() # obj._Foo__f2() class Bar(Foo):#父類為Foo def __f2(self): # _Bar__f2 print("Bar.f2") obj = Bar() obj.f1()
四、繼承的實作原理
# coding:utf-8 (在python2中要寫檔案頭才能保證不亂碼,python3底層會有優化機制不用寫)
1、 補充知識:
新式類:但凡是繼承了object類的子類,以該子類子子孫孫類都稱之為新式類
經典類:沒有繼承了object類的子類,以該子類子子孫孫類都稱之為經典類
python3中無論是否繼承object,都默認繼承object,即python3中全都是新式類,
python2中才有經典類
python2中沒有顯式的繼承object的類,以及該類的子類,都是經典類;
python2中顯式地宣告繼承object的類,以及該類的子類,都是新式類,
pyhon2中新式類要主動繼承,手動加上object,加上檔案頭
class Foo(object):
pass
print(Foo.__bases__) #通過類的內置屬性__bases__可以查看類繼承的所有父類
2、 繼承的實作原理
繼承(先抽象再繼承):是基于抽象的結果,通過編程語言去實作它,肯定是先經歷抽象這個程序,才能通過繼承的方式去表達出抽象的結構,
對于你定義的每一個類,Python都會計算出一個方法決議順序(MRO)串列,該MRO串列就是一個簡單的所有基類的線性順序串列
python會在MRO串列上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止
查找順序:(1)子類會先于父類被檢查
(2)多個父類會根據它們在串列中的順序被檢查
(3)如果對下一個類存在兩個合法的選擇,選擇第一個父類
ps:
1.由物件發起的屬性查找,會從物件自身的屬性里檢索,沒有則會按照物件的類.mro()規定的順序依次找下去,
2.由類發起的屬性查找,會按照當前類.mro()規定的順序依次找下去
2.1 菱形問題(有時也稱死亡鉆石):一個子類繼承的多條件分支最侄訓聚到一個非object類,在菱形繼承下
新式類與經典類關于屬性查找的方式不同
新式類:廣度優先
經典類:深度優先
# 例1:非菱形繼承,經典類與新式類的屬性查找順序都一樣 class E: def test(self): print('from E') pass class F: def test(self): print('from F') class B(E): def test(self): print('from B') pass class C(F): def test(self): print('from C') class D: def test(self): print('from D') class A(B, C, D): def test(self): print('from A') pass obj=A() obj.test()
# 例2:菱形繼承 class G(object): # 在python2中,未繼承object的類及其子類,都是經典類 def test(self): print('from G') pass class E(G): def test(self): print('from E') pass class F(G): def test(self): print('from F') pass class B(E): def test(self): print('from B') pass class C(F): def test(self): print('from C') pass class D(G): def test(self): print('from D') pass class A(B,C,D): def test(self): print('from A') pass obj=A() obj.test() print(A.mro())
五、mixins機制
mixins機制 遵循'is-a'關系
#不合理 class Vehicle: # 交通工具 def fly(self): ''' 飛行功能相應的代碼 ''' print("I am flying") class CivilAircraft(Vehicle): # 民航飛機 pass class Helicopter(Vehicle): # 直升飛機 pass class Car(Vehicle): # 汽車并不會飛,但按照上述繼承關系,汽車也能飛了 pass
#Mixins機制 class Vehicle: # 交通工具 pass class FlyableMixin: def fly(self): ''' 飛行功能相應的代碼 ''' print("I am flying") class CivilAircraft(FlyableMixin, Vehicle): # 民航飛機 pass class Helicopter(FlyableMixin, Vehicle): # 直升飛機 pass class Car(Vehicle): # 汽車 pass # ps: 采用某種規范(如命名規范)來解決具體的問題是python慣用的套路
使用Mixin類實作多重繼承要非常小心
- 首先它必須表示某一種功能,而不是某個物品,python 對于mixin類的命名方式一般以 Mixin, able, ible 為后綴
- 其次它必須責任單一,如果有多個功能,那就寫多個Mixin類,一個類可以繼承多個Mixin,為了保證遵循繼承的“is-a”原則,只能繼承一個標識其歸屬含義的父類
- 然后,它不依賴于子類的實作
- 最后,子類即便沒有繼承這個Mixin類,也照樣可以作業,就是缺少了某個功能,(比如飛機照樣可以載客,就是不能飛了)
? Mixins是從多個類中重用代碼的好方法,但是需要付出相應的代價,我們定義的Minx類越多,子類的代碼可讀性就會越差,并且更惡心的是,在繼承的層級變多時,代碼閱讀者在定位某一個方法到底在何處呼叫時會暈頭轉向
---26---
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/63444.html
標籤:Python
上一篇:Python Selenium 實戰教學:爬取每日天氣
下一篇:python 內置函式
