1、什么是繼承
我們接下來來聊聊Python代碼中的“繼承”:類是用來描述現實世界中同一組事務的共有特性的抽象模型,但是類也有上下級和范圍之分,比如:生物 => 動物 => 哺乳動物 => 靈長型動物 => 人類 => 黃種人
從哲學上說,就是共性與個性之間的關系,比如:白馬和馬!所以,我們在OOP代碼中,也一樣要體現出類與類之間的共性與個性關系,這里就需要通過類的繼承來體現。簡單來說,如果一個類A使用了另一個類B的成員(屬性和方法),我們就可以說A類繼承了B類,同時這也體現了OOP中代碼重用的特性!
2、繼承的基本語法
假設A類要繼承B類中的所有屬性和方法(私有屬性和私有方法除外)
class B(object):
? ? pass
clss A(B):
? ? pass
a = A()
a.B中的所有公共屬性
a.B中的所有公共方法
案例:Person類與Teacher、Student類之間的繼承關系
class Person(object):
? ? def eat(self):
? ? ? ? print('i can eat food!')
? ? def speak(self):
? ? ? ? print('i can speak!')
? ? ? ??
class Teacher(Person):
? ? pass
class Student(Person):
? ? pass
teacher = Teacher()
teacher.eat()
teacher.speak()
student = Student()
student.eat()
studnet.speak()
3、與繼承相關的幾個概念
繼承:一個類從另一個已有的類獲得其成員的相關特性,就叫作繼承!
派生:從一個已有的類產生一個新的類,稱為派生!
很顯然,繼承和派生其實就是從不同的方向來描述的相同的概念而已,本質上是一樣的!
父類:也叫作基類,就是指已有被繼承的類!
子類:也叫作派生類或擴展類
擴展:在子類中增加一些自己特有的特性,就叫作擴展,沒有擴展,繼承也就沒有意義了!
單繼承:一個類只能繼承自一個其他的類,不能繼承多個類,單繼承也是大多數面向對象語言的特性!
多繼承:一個類同時繼承了多個父類, (C++、Python等語言都支持多繼承)
4、單繼承
單繼承:一個類只能繼承自一個其他的類,不能繼承多個類。這個類會有具有父類的屬性和方法。
基本語法:
# 1、定義一個共性類(父類)
class Person(object):
? ? pass
# 2、定義一個個性類(子類)
class Teacher(Person):
? ? pass
案例:比如汽車可以分為兩種類型(汽油車、電動車)
# 1、定義一個共性類(車類)
class Car(object):
? ? def run(self):
? ? ? ? print('i can run')
# 2、定義汽油車
class GasolineCar(Car):
? ? pass
# 3、定義電動車
class EletricCar(Car):
? ? pass
bwm = GasolineCar()
bwm.run()
5、單繼承特性:傳遞性
在Python繼承中,如A類繼承了B類,B類又繼承了C類。則根據繼承的傳遞性,則A類也會自動繼承C類中所有屬性和方法(公共)
class C(object):
? ? def func(self):
? ? ? ? print('我是C類中的相關方法func')
? ? ? ??
class B(C):
? ? pass
class A(B):
? ? pass
a = A()
a.func()
6、編寫面向對象代碼中的常見問題
答:在Python中,類理論上是不區分大小寫的。但是要遵循一定的命名規范:首字母必須是字母或下劃線,其中可以包含字母、數字和下劃線,而且要求其命名方式采用大駝峰。
電動汽車:EletricCar
父類:Father
子類:Son
問題2:父類一定要繼承object么?Car(object)
答:在Python面向對象代碼中,建議在編寫父類時,讓其自動繼承object類。但是其實不寫也可以,因為默認情況下,Python中的所有類都繼承自object。
問題3:打印屬性和方法時,都喜歡用print
class Person():
? ? def __init__(self, name):
? ? ? ? self.name = name
? ? ? ??
? ? def speak(self):
? ? ? ? print('i can speak')
? ? ? ??
# 創建對象,打印屬性和方法
p = Person('Tom')
print(p.name)
p.speak()
7、多繼承
什么是多繼承?
Python語言是少數支持多繼承的一門編程語言,所謂的多繼承就是允許一個類同時繼承自多個類的特性。
基本語法:
class B(object):
? ? pass
class C(object):
? ? pass
class A(B, C):
? ? pass
a = A()
a.B中的所有屬性和方法
a.C中的所有屬性和方法
案例:汽油車、電動車 => 混合動力汽車(汽車 + 電動)
class GasolineCar(object):
? ? def run_with_gasoline(self):
? ? ? ? print('i can run with gasoline')
? ? ? ??
class EletricCar(object):
? ? def run_with_eletric(self):
? ? ? ? print('i can run with eletric')
? ? ? ??
class HybridCar(GasolineCar, EletricCar):
? ? pass
tesla = HybridCar()
tesla.run_with_gasoline()
tesla.run_with_eletric()
注意:雖然多繼承允許我們同時繼承自多個類,但是實際開發中,應盡量避免使用多繼承,因為如果兩個類中出現了相同的屬性和方法就會產生命名沖突。
8、子類擴展:重寫父類屬性和方法
擴展特性:繼承讓子類繼承父類的所有公共屬性和方法,但是如果僅僅是為了繼承公共屬性和方法,繼承就沒有實際的意義了,應該是在繼承以后,子類應該有一些自己的屬性和方法。
什么是重寫?
重寫也叫作覆蓋,就是當子類成員與父類成員名字相同的時候,從父類繼承下來的成員會重新定義!
此時,通過子類實例化出來的對象訪問相關成員的時候,真正其作用的是子類中定義的成員!
上面單繼承例子中 Animal 的子類 Cat和Dog 繼承了父類的屬性和方法,但是我們狗類Dog 有自己的叫聲'汪汪叫',貓類 Cat 有自己的叫聲 '喵喵叫' ,這時我們需要對父類的 call() 方法進行重構。如下:
class Animal(object):
? ? def eat(self):
? ? ? ? print('i can eat')
? ??
? ? def call(self):
? ? ? ? print('i can call')
? ? ? ??
class Dog(Animal):
? ? pass
class Cat(Animal):
? ? pass
wangcai = Dog()
wangcai.eat()
wangcai.call()
miaomiao = Cat()
miaomiao.eat()
miaomiao.call()
Dog、Cat子類重寫父類Animal中的call方法:
class Animal(object):
? ? def eat(self):
? ? ? ? print('i can eat')
? ? # 公共方法
? ? def call(self):
? ? ? ? print('i can call')
class Dog(Animal):
? ? # 重寫父類的call方法
? ? def call(self):
? ? ? ? print('i can wang wang wang')
class Cat(Animal):
? ? # 重寫父類的call方法
? ? def call(self):
? ? ? ? print('i can miao miao miao')
wangcai = Dog()
wangcai.eat()
wangcai.call()
miaomiao = Cat()
miaomiao.eat()
miaomiao.call()
思考:重寫父類中的call方法以后,此時父類中的call方法還在不在?
答:還在,只不過是在其子類中找不到了。類方法的調用順序,當我們在子類中重構父類的方法后,Cat子類的實例先會在自己的類 Cat 中查找該方法,當找不到該方法時才會去父類 Animal 中查找對應的方法。
9、super()調用父類屬性和方法
super():調用父類屬性或方法,完整寫法:super(當前類名, self).屬性或方法()
,在Python3以后版本中,調用父類的屬性和方法我們只需要使用super().屬性或super().方法名()
就可以完成調用了。
案例:Car汽車類、GasolineCar汽油車、ElectricCar電動車
class Car(object):
? ? def __init__(self, brand, model, color):
? ? ? ? self.brand = brand
? ? ? ? self.model = model
? ? ? ? self.color = color
? ? ?def run(self):
? ? ? ? print('i can run')
? ? ? ??
class GasolineCar(Car):
? ? def __init__(self, brand, model, color):
? ? ? ? super().__init__(brand, model, color)
? ? ? ??
? ? def run(self):
? ? ? ? print('i can run with gasoline')
? ? ? ??
class ElectricCar(Car):
? ? def __init__(self, brand, model, color):
? ? ? ? super().__init__(brand, model, color)
? ? ? ? # 電池屬性
? ? ? ? self.battery = 70
? ? ? ??
? ? def run(self):
? ? ? ? print(f'i can run with electric,remain:{self.battery}')
? ? ? ??
bwm = GasolineCar('寶馬', 'X5', '白色')
bwm.run()
tesla = ElectricCar('特斯拉', 'Model S', '紅色')
tesla.run()
10、MRO屬性或MRO方法:方法解析順序
MRO(Method Resolution Order):方法解析順序,我們可以通過類名.__mro__
或類名.mro()
獲得“類的層次結構”,方法解析順序也是按照這個“類的層次結構”尋找到。
class Car(object):
? ? def __init__(self, brand, model, color):
? ? ? ? self.brand = brand
? ? ? ? self.model = model
? ? ? ? self.color = color
? ? ?def run(self):
? ? ? ? print('i can run')
? ? ? ??
class GasolineCar(Car):
? ? def __init__(self, brand, model, color):
? ? ? ? super().__init__(brand, model, color)
? ? ? ??
? ? def run(self):
? ? ? ? print('i can run with gasoline')
? ? ? ??
class ElectricCar(Car):
? ? def __init__(self, brand, model, color):
? ? ? ? super().__init__(brand, model, color)
? ? ? ? # 電池屬性
? ? ? ? self.battery = 70
? ? ? ??
? ? def run(self):
? ? ? ? print(f'i can run with electric,remain:{self.battery}')
? ? ? ??
print(ElectricCar.__mro__)
print(ElectricCar.mro())
說明:有MRO方法解析順序可知,在類的繼承中,當某個類創建了一個對象時,調用屬性或方法,首先在自身類中去尋找,如找到,則直接使用,停止后續的查找。如果未找到,繼續向上一級繼承的類中去尋找,如找到,則直接使用,沒有找到則繼續向上尋找...直到object類,這就是Python類繼承中,其方法解析順序。
綜上:object類還是所有類的基類(因為這個查找關系到object才終止)