任性插入:
繼承的時候,如果子類中沒有初始化函數,但是要去看看父類中有沒有初始化函數,再決定子類在實例化的時候要不要傳參;
子類中的方法想要調用父類中的方法,self.方法名;
子類中的方法想使用類中的其他方法也是加上self.;
1.面向對象三大特性:
封裝 根據 職責 將 屬性 和 方法 封裝 到一個抽象的 類 中;
繼承 實現代碼的重用,相同的代碼不需要重復的編寫;
多態 不同的對象調用相同的方法,產生不同的執行結果,增加代碼的靈活度;
補充:
【轉自別人】
繼承好處:
提升代碼的重用率:
有利於代碼的管理,在需要改代碼的時候,只需要在父類中修改,不需要動子類中的代碼。
單繼承和多繼承(但是在java中繼承只能是單繼承,其余的語言不清楚)

class Father(): pass
class Mather(): pass
class Son(Father):##########單繼承
pass
class Daughter(Father,Mather):##########多繼承
pass
2.什么時候用組合,什么時候用繼承?
(1)當類之間有顯著不同,並且較小的類是較大的類所需要的組件時,用組合比較好;
比如說一架車子是由不同的組件組合起來的,這樣類似的即用組合,把全部的零件組裝成一個完整的整體。
(2)當類之間有很多相同的功能,把這些共同的功能寫成父類,子類去繼承就可以,用繼承比較好;
比如小貓小狗人都有吃喝拉睡的動作,如果在各自的類中都要寫吃喝拉睡的方法,那重復的代碼太多,那就可以使用繼承,寫個動物類中有吃喝拉睡,小貓小狗人調用即可。
3.繼承的作用:
(1)減少重復代碼,子類可擴展或者可以修改【但是往往在實踐中,該含義意義並不很大,甚至常常是有害的,因為它使得子類與基類出現強耦合。】
(2)聲明某個子類兼容於某基類,定義一個接口類,子類繼承接口類,並且在子類實現接口中定義的方法————————————接口繼承
【目的:規范子類,子類實現接口類的中定義的方法,並且不必要實例化】
【copy來的:接口繼承實質上是要求“做出一個良好的抽象,這個抽象規定了一個兼容接口,使得外部調用者無需關心具體細節,
可一視同仁的處理實現了特定接口的所有對象”一這在程序設計上, 叫做歸一化。】————個人感覺意思就是:任何一個子類要調用接口類都必須要實現其定義的方法,
子類想怎么實現就怎么實現,不關其他任何人的事情,當然子類還可以有屬於自己的方法【類似java中的接口。。。。】。
4.繼承的MRO順序:
在經典類中,沒有繼承object類
在新式類中,有繼承object類
在python3中,所有類最頂層父類都是object類,與java類似,如果定義類的時候沒有寫出父類,則object類就是其直接父類。
現在的問題是,如果多個父類中包含了同名的方法,此時會發生什么呢?此時排在前面的父類中的方法會“遮蔽”排在后面的父類中的同名方法。

class Father(object):#######新式類
pass
class Mather():##########經典類
pass
但是,這一切在python3出現之后發生了變化,因為在python3里面創建的都是新式類。
不管它倆的變化,我們目前關注的是兩種類在多繼承狀態下查找“方法”的順序。
經典類:深度查找
新式類:廣度查找
經典類順序(深度):F---D---B--A后F---E---C---A
新式類順序(廣度):F--D---B(不找基類)后F---E--C--A
但是在新式類中,對於程序猿定義的每一個類,python會計 算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表
為了實現繼承.python會在MRO列表上從左到右開始查找基類,當到找到第一個匹配這個屬生的類為止,
而這個MRO列表的構造是通過一個C3線性化算法來實現的。它實際上就是合並所有父類的MRO列表並遵循如下三條准則:
(1)子類會先於父類被檢查【類似作用域】
(2)多個父類會根據它們在列表中的順序被檢查
(3)如果對下一個類存在兩個合法的選擇,選擇第一個父類;
新式類可以直接通過 類名.__mro__ 的方式獲取類的 MRO,也可以通過 類名.mro() 的形式。

class Father(): print("這個是父親") class Mather(): print("這個是母親") class Son(Father):##########單繼承
print("這個是兒子") class Son1(Father,Mather):##########多繼承
print("這個是兒子") class Daughter(Father,Mather):##########多繼承
print("這個是女兒") print(Son1.__mro__) print(Daughter.__mro__) ###################
這個是父親 這個是母親 這個是兒子 這個是兒子 這個是女兒 (<class '__main__.Son1'>, <class '__main__.Father'>, <class '__main__.Mather'>, <class 'object'>) (<class '__main__.Daughter'>, <class '__main__.Father'>, <class '__main__.Mather'>, <class 'object'>)
重寫:
子類包含與父類同名的方法的現象被稱為方法重寫(Override),也被稱為方法覆蓋。可以說子類重寫了父類的方法,也可以說子類覆蓋了父類的方法。
通過使用未綁定方法即可在子類中再次調用父類中被重寫的方法
【在通過類名調用實例方法時,Python 不會為實例方法的第一個參數 self 自動綁定參數值,而是需要程序顯式綁定第一個參數 self。這種機制被稱為未綁定方法。】

class Fruit(): def name(self): print('我是所有水果的父類') class Apple(Fruit): def name(self): print('我重寫了Fruit的name方法——蘋果') def run_fruit(self): # 直接執行name方法,將會掉喲個子類重寫之后的name方法 self.name() # 使用類名調用實例方法(未綁定方法)調用父類被重寫的方法 Fruit.name(self) apple=Apple() apple.name() apple.run_fruit() ########################## 我重寫了Fruit的name方法——蘋果 我重寫了Fruit的name方法——蘋果 我是所有水果的父類
5.接口繼承
接口是一組功能的入口,要調用某一組功能,需要通過接口來進行調用,而不需要關注這組功能是如何實現的,要的只是結果。
在類里,接口是提取了一群類共同的函數,可以把接口當做一個函數的集合。
正如2所說的,接口父類只是定義有什么方法,但是並不具體實現其方法體,當有子類去繼承該父類時候,需要具體去實現這些方法體。

1 class Animal(): 2 def eat(self): 3 pass
4 def read(self): 5 pass
6
7 class Cat(Animal): 8 def eat(self,name): 9 print('%s 在吃魚' %name) 10
11 def read(self,name): 12 print('%s 在讀書' %name) 13 a=Animal() 14 print(a.eat()) 15 c=Cat() 16 c.eat("周周") 17 c.eat("小周周") 18
19 ############
20
21 None 22 周周 在吃魚 23 小周周 在吃魚
6.抽象類
抽象類的本質上也是類,但是抽象類只能夠被繼承,不能進行實例化,也就是說可以當父類,但是不能生成對象。
抽象類介於接口和歸一化中間,用於實現接口的歸一化
當子類繼承抽象類的時候,如果抽象類定義了抽象方法,那么子類必須要定義同名的方法。即父類限制:
1、子類必須要有父類的方法
2、子類實現的方法必須跟父類的方法的名字一樣
python的抽象類通過abc模塊實現。

import abc class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod def eat(self): pass @abc.abstractmethod def read(self): pass
class Cat(Animal): def eat(self,name): print('%s 在吃魚' %name) def read(self,name): print('%s 在讀書' %name) ###a=Animal() #####注意注意,不能實例化,否則報錯 #####TypeError: Can't instantiate abstract class Animal with abstract methods eat, read
c=Cat() c.eat("周周") c.eat("小周周") ######
周周 在吃魚 小周周 在吃魚
7.super方法調用父類的數據屬性和函數屬性
Python 要求,如果子類重寫了父類的構造方法,那么子類的構造方法必須調用父類的構造方法。
子類的構造方法調用父類的構造方法有兩種方式:
- 使用未綁定方法,這種方式很容易理解。因為構造方法也是實例方法,當然可以通過這種方式來調用。
- 使用 super() 函數調用父類的構造方法。
【注意,當子類繼承多個父類是,super() 函數只能用來調用第一個父類的構造方法,而其它父類的構造方法只能使用未綁定的方式調用。】
在繼承中基類的構造(__init__()方法)不會被自動調用,它需要在其派生類的構造中親自專門調用,使用super().__init__()或parentClassName.__init__()或者其他方式。【書寫的方式有點點不同】
重寫了就只會調用子類中的重寫的方法;

''' 重寫:子類和父類里面有相同的函數名 擴展:子類有父類里面沒有的方法 ''' class Parent(): def __init__(self,name,age): self.name=name self.age=age def msg(self): print('我是父類!!!!') class Son(Parent): def __init__(self,name,age,job): super().__init__(name,age) self.job=job def msg(self): print('我是子類============') def job_msg(self): print('我的名字是:{0},年齡{1},工作是:{2}'.format(self.name,self.age,self.job)) son=Son('jack','25','python測試工程師') son.msg() son.job_msg() ########################## 我是子類============ 我的名字是:jack,年齡25,工作是:python測試工程師

class Vehicle1: Country='China'
def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print('開動啦') print('開動啦') class Subway(Vehicle1): def __init__(self,name,speed,load,power,line): ###使用父類的數據屬性
# Vehicle.__init__(self,name,speed,load,power)###如果是使用父類的名字,那在修改后,子類的就很麻煩修改
super().__init__(name,speed,load,power)###super就不用修改咯
#super(__class__,self).__init__(name,speed,load,power)###三種方式均可以
#super(Subway,self).__init__(name,speed,load,power)
self.line=line def show_info(self): print(self.name,self.speed,self.load,self.power,self.line) def run(self): ###調用父類的方法
# Vehicle.run(self)
super().run() print('%s %s 號線,開動啦' %(self.name,self.line)) line2=Subway('成都地鐵','100km/h',1000000000,'電',2) line2.show_info() line2.run() print(line13.__class__) ########
成都地鐵 100km/h 1000000000 電 2 開動啦 成都地鐵 2 號線,開動啦 <class '__main__.Subway'>
super()是一個特殊的函數,將父類跟子類關聯起來,super()._init_(),,其作用是將子類包含父類的所有屬性。
【為避免多繼承報錯,使用不定長參數,接受參數
】

__author__ = 'Administrator' class Parent(object): def __init__(self,name): print("Parent的__init__方法開始!!調用") self.name=name print("Parent的__init__方法結束==調用") class Son1(Parent): def __init__(self,name,age): print("Son1的__init__方法開始調用") self.age=age Parent.__init__(self,name) print("Son1的__init__方法結束調用") class Son2(Parent): def __init__(self,name,gender): print("Son2的__init__方法開始調用") self.gender=gender Parent.__init__(self,name) print("Son2的__init__方法結束調用") class Grandson(Son1,Son2): def __init__(self,name,age,gender): print("Grandson的__init__方法開始調用") Son1.__init__(self,name,age) Son2.__init__(self,name,gender) print("Grandson的__init__方法結束調用") grandson=Grandson("孫子",18,"男") ############################ Grandson的__init__方法開始調用 Son1的__init__方法開始調用 Parent的__init__方法開始!!調用 Parent的__init__方法結束==調用 Son1的__init__方法結束調用 Son2的__init__方法開始調用 Parent的__init__方法開始!!調用 Parent的__init__方法結束==調用 Son2的__init__方法結束調用 Grandson的__init__方法結束調用

___author__ = 'Administrator' class Parent(object): def __init__(self,name,*args,**kargs): print("Parent的__init__方法開始!!調用") self.name=name print("Parent的__init__方法結束==調用") class Son1(Parent): def __init__(self,name,age,*args,**kargs): print("Son1的__init__方法開始調用") self.age=age super().__init__(name,*args,**kargs) print("Son1的__init__方法結束調用") class Son2(Parent): def __init__(self,name,gender,*args,**kargs): print("Son2的__init__方法開始調用") self.gender=gender super().__init__(self,name,*args,**kargs) print("Son2的__init__方法結束調用") class Grandson(Son1,Son2): def __init__(self,name,age,gender): print("Grandson的__init__方法開始調用") super().__init__(name,age,gender) print("Grandson的__init__方法結束調用") grandson=Grandson("孫子",18,"男") ############################## Grandson的__init__方法開始調用 Son1的__init__方法開始調用 Son2的__init__方法開始調用 Parent的__init__方法開始!!調用 Parent的__init__方法結束==調用 Son2的__init__方法結束調用 Son1的__init__方法結束調用 Grandson的__init__方法結束調用

___author__ = 'Administrator' class Parent(object): def __init__(self,name,*args,**kargs): print("Parent的__init__方法開始!!調用") self.name=name print("Parent的__init__方法結束==調用") class Son1(Parent): def __init__(self,name,age,*args,**kargs): print("Son1的__init__方法開始調用") self.age=age super().__init__(name,*args,**kargs) print("Son1的__init__方法結束調用") class Son2(Parent): def __init__(self,name,gender,*args,**kargs): print("Son2的__init__方法開始調用") self.gender=gender super().__init__(self,name,*args,**kargs) print("Son2的__init__方法結束調用") class Grandson(Son1,Son2): def __init__(self,name,age,gender): print("Grandson的__init__方法開始調用") super().__init__(name,age,gender) print("Grandson的__init__方法結束調用") print(Grandson.__mro__) grandson=Grandson("孫子",18,"男") ################################# (<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>) Grandson的__init__方法開始調用 Son1的__init__方法開始調用 Son2的__init__方法開始調用 Parent的__init__方法開始!!調用 Parent的__init__方法結束==調用 Son2的__init__方法結束調用 Son1的__init__方法結束調用 Grandson的__init__方法結束調用
通過父類名調用的時候,parent調用了兩次;
使用super的時候,parent 只是執行了一次;

___author__ = 'Administrator' class Parent(object): def __init__(self,name): print("Parent的__init__方法開始!!調用") self.name=name print("Parent的__init__方法結束==調用") class Son(Parent): def __init__(self,name,age): print("Son的__init__方法開始調用") self.age=age super().__init__(name)# 單繼承不能提供全部參數 print("Son的__init__方法結束調用") class Grandson(Son): def __init__(self,name,age,gender): print("Grandson的__init__方法開始調用") super().__init__(name,age)# 單繼承不能提供全部參數 print("Grandson的__init__方法結束調用") grandson=Grandson("孫子",18,"男") ########################### Grandson的__init__方法開始調用 Son的__init__方法開始調用 Parent的__init__方法開始!!調用 Parent的__init__方法結束==調用 Son的__init__方法結束調用 Grandson的__init__方法結束調用
【轉自別人:】
總結:
- super().__init__相對於類名.__init__,在單繼承上用法基本無差;
- 但在多繼承上有區別,super方法能保證每個父類的方法只會執行一次,而使用類名的方法會導致方法被執行多次,具體看前面的輸出結果;
- 多繼承時,使用super方法,對父類的傳參數,應該是由於python中super的算法導致的原因,必須把參數全部傳遞,否則會報錯;
- 單繼承時,使用super方法,則不能全部傳遞,只能傳父類方法所需的參數,否則會報錯,
- 多繼承時,相對於使用類名.__init__方法,要把每個父類全部寫一遍, 而使用super方法,只需寫一句話便執行了全部父類的方法,這也是為何多繼承需要全部傳參的一個原因。
- 不知道是不是重復了:具有兩個父類的屬性和方法,如果兩個父類具有同名方法的時候,就近原則(__init__也是)。
8.
在調用父類的方法時,需要加上基類的類名前綴,且需要帶上self參數變量。區別於在類中調用普通函數時並不需要帶上self參數;
重寫父類方法——————————對於父類的方法,如果有不符合子類想要做的事情,可以對父類的方法進行重寫,重寫時要與父類的方法同名,這樣python將不會考慮父類的方法,而只是關注子類定義的相應的方法。
9.
isinstance(obj,cls)判斷是否obj是否是類 cls 的對象
issubclass(sub, super)判斷sub類是否是 super 類的派生類

1 class Person(): 2 pass 3 class Man(Person): 4 pass 5 p=Person() 6 m=Man() 7 print(isinstance(p,Person)) 8 print(isinstance(m,Person))#####因為有了繼承的關系 9 print(isinstance(p,Man)) 10 print(issubclass(Man,Person)) 11 12 ###################### 13 True 14 True 15 False 16 True
10.多態:同一個方法在不同的類中最終呈現出不同的效果,即為多態。

class Fruit(): def name(self): print('我是水果') class Apple(Fruit): def name(self): print('我是蘋果') Fruit().name() Apple().name()