您現在的位置是:首頁 > 遊戲
類的繼承和多型,簡易的Python面向物件教程
說明類的繼承和多型有什麼作用
作者:麥叔
面向物件是所有高階語言(Python,Java,C++等)的基石,是重中之重。
這個文章系列的目的是透過簡單易懂的例子,深入淺出,讓Python學習者牢固的掌握Python面向物件的概念和方法。
本系列包括:
面向物件(1) - 屬性,構造方法,self關鍵詞。
面向物件(2) - 例項方法 (本文)
面向物件(3) - 類屬性和類方法
面向物件(4) - 繼承和多型,以及一個綜合小遊戲案例
類的繼承,父類,子類
看這張圖:
上面有一條小狗,代表了普通的狗。
下面有警犬,牧羊犬和寵物犬,他們都是狗。
但他們又有獨特的特點,具有額外的屬性或者技能。
警犬有偵探功能,所以有detect()方法,有額外的屬性ability,表示它的偵探能力等級。
牧羊犬有保護養的功能,所以有protect()方法,有額外的num_of_sheeps表示它可以保護幾隻羊。
寵物犬有唱歌的功能,所以有sing()方法,有額外的屬性price表示價格。
動物界具有天然的繼承關係,人類也是,我們一代代繼承下來。繼承了前輩們的屬性和能力,又發展了自己獨特的屬性和能力。
在圖中的例子,我們如何在程式中表示普通的狗,牧羊犬,警犬等呢?
我們可以把detect(), protect()等函式和屬性直接加在Dog裡面,但這並不合理,因為並不是所有的狗可以偵查,並不是所有的狗都可以保護養。
正確的作法是建立新的類,這些新的類繼承Dog類:
SheepDog 表示牧羊犬
PoliceDog 表示警犬
PetDog 表示寵物犬
在這裡Dog被稱為
父類
,SheepDog等被稱為
子類
。
子類會自動擁有父類的屬性和方法,自己也可以新增自己的獨特屬性和方法。
子類的定義
現在來定義SheepDog。先看看我們原來的Dog類:
#類是一個模板
class Dog:
num_of_dogs = 0 # 類屬性
police_height = 60
#構造方法 - 新增例項屬性,做其他的初始化工作
def __init__(self, name, height, power):
self。name = name
self。height = height
self。power = power
self。blood = 10
print(f“{self。name}出生了,汪汪!”)
Dog。num_of_dogs += 1
#狗叫
def bark(self):
print(f‘我是{self。name},汪汪汪!’)
定義子類SheepDog
class SheepDog(Dog):
‘’‘牧羊犬,包括名字,高度,攻擊力和能看護的養的個數’‘’
def __init__(self, name, height, power, num_of_sheeps):
super()。__init__(name, height, power)
self。num_of_sheeps = num_of_sheeps
仔細閱讀上面的程式碼,觀察它的特點:
宣告繼承關係
SheepDog(Dog)
這種寫法:括號中的Dog表示Dog是SheepDog的父類。
我們定義Dog的時候沒有括號,表示它沒有父類(實際上它預設繼承了Object類)。
建構函式和super()方法
1。子類也有建構函式init方法,傳入各項必要的屬性。
2。建構函式的第一行呼叫父類的建構函式,因為牧羊犬首先也是一個Dog,所以要先構造一個Dog出來。
3。其中super()代表父類。我們用self表示自己,用super()表示父類。注意self是一個關鍵詞,是沒有括號的,super()是一個函式,是有括號的。
4。值得注意的是,使用self可以訪問父類的屬性和方法,因為父類的就是自己的。在建構函式中我們使用super()來呼叫父類的建構函式是因為子類和父類都有__init__方法,如果不適用super()就會呼叫自己的__init__方法,這種情況下需要用super)()來明確指定要訪問父類的方法。
5。第二行添加了牧羊犬的獨特屬性num_of_sheeps。這樣牧羊犬有4個屬性,其中3個屬性是繼承自父類的,一個是自己獨有的。
使用子類
子類的使用和父類是一樣的:
呼叫建構函式建立例項。
透過變數名訪問屬性。
透過變數名呼叫方法。注意bark()是父類的函式,子類可以直接使用。
sd1 = SheepDog(‘大黃’, 67, 88, 10)
print(f‘名字:{sd1。name}’)
print(f‘血量:{sd1。blood}’)
print(f‘高度:{sd1。power}’)
sd1。bark()
給子類新增新的方法
我們給SheepDog新增它的獨特方法protect():
class SheepDog(Dog):
‘’‘牧羊犬,包括名字,高度,攻擊力和能看護的養的個數’‘’
def __init__(self, name, height, power, num_of_sheeps):
super()。__init__(name, height, power)
self。num_of_sheeps = num_of_sheeps
def protect(self):
print(‘我開始保護小羊啦!’)
呼叫一下試試看:
sd1 = SheepDog(‘大黃’, 67, 88, 10)
sd1。protect()
覆蓋父類的方法
因為繼承的關係,SheepDog直接就有bark()方法,這是從父類繼承過來的。
假設牧羊犬的叫聲和普通叫聲是不一樣的,我們在子類中
覆蓋
父類中的方法:
class SheepDog(Dog):
‘’‘牧羊犬,包括名字,高度,攻擊力和能看護的養的個數’‘’
def __init__(self, name, height, power, num_of_sheeps):
super()。__init__(name, height, power)
self。num_of_sheeps = num_of_sheeps
def protect(self):
print(‘我開始保護小羊啦!’)
def bark(self):
print(‘我是牧羊犬,我驕傲!’)
這時候再呼叫bark()方法就會使用子類中定義的方法:
sd1 = SheepDog(‘大黃’, 67, 88, 10)
sd1。bark()
列印的結果是:
我是牧羊犬,我驕傲!
整合和覆蓋的用處舉例
類的繼承和對父類方法的覆蓋在程式碼設計中很有用。假設有個程式的介面是這樣的:
按鈕就是一個類,比如叫做Button。
為了實現不同的面板,我們可以寫一個類繼承Button類,假設就叫做MyButton吧,子類自動擁有了父類的屬性和函式,但是我們可以覆蓋某些函式,讓他擁有不同的面板,甚至不同的行為。
Dog版本的吃雞遊戲
面向物件的核心知識到這裡就更新完了,最後奉上Dog版本的吃雞遊戲。這個遊戲包含兩個類:
其中dog。py定義了幾個狗類
game。py中建立100條Dog並讓他們互相攻擊,直到最後只有一隻為止。
dog。py
#2種狗具有不同的攻擊力和防禦能力。攻擊強的防禦弱;反之亦然;
import random
class Dog:
dogs = [] #儲存所有活著的Dog
def __init__(self, name):
self。name = name
self。blood = 100
self。attack_power = 5
self。defense_power = 3
#攻擊!
def attack(self, dog2):
print(f‘{self。name}攻擊{dog2。name},攻擊力:{self。attack_power},防禦力:{dog2。defense_power}’)
point = self。attack_power - dog2。defense_power
if(dog2。blood > point):
dog2。blood -= point
print(f‘{dog2。name}受到攻擊,奮力自救,血量減少為{dog2。blood}’)
else:
dog2。blood = 0
print(f‘{dog2。name}受到攻擊,失血過多,死亡!’)
Dog。dogs。remove(dog2)
#判定狗的型別
def dog_type(self):
if(isinstance(self, SheepDog)):
return ‘牧羊犬’
elif(isinstance(self, PoliceDog)):
return ‘警犬’
else:
return ‘普通犬’
#牧羊犬
class SheepDog(Dog):
def __init__(self, name):
super()。__init__(name)
self。attack_power = random。randint(5, 10)
self。defense_power = random。randint(3,5)
print(‘牧羊犬{self。name}問世!’)
self。dogs。append(self)
#警犬
class PoliceDog(Dog):
def __init__(self, name):
super()。__init__(name)
self。attack_power = random。randint(8, 13)
self。defense_power = random。randint(1,3)
print(‘♀警犬{self。name}問世!’)
self。dogs。append(self)
game。py
#1。 首先建立100個Dog, 50個SheepDog, 50個PoliceDog
#2。 每一輪遊戲,隨機選出2個Dog
#3。 dog1先攻擊dog2,然後dog2攻擊dog1
#3。 任何一方血量變為0就表明死亡!死亡的Dog退出遊戲。
#4。 最後只有一個Dog了,遊戲結束,勝利者可以吃雞。
from dog import *
import random #產生隨機數字
import time #時間模組
#1。建立100條狗
for i in range(100):
if(i%2==0):
SheepDog(i+1) #建立1個牧羊犬
else:
PoliceDog(i+1) #建立1個警犬
#2。 開始遊戲迴圈
while(True):
#判斷是否只有1個Dog
if(len(Dog。dogs) == 1):
winner = Dog。dogs[0]
print(‘’)
print(‘大吉大利,今晚吃雞!’)
print(f‘贏家是:{winner。dog_type()} {winner。name}’)
print(‘’)
break
dog1, dog2 = random。sample(Dog。dogs, 2)
dog1。attack(dog2)
dog2。attack(dog1)
time。sleep(0。02)
推薦文章
- “巴掌大”的肉包子製作,下午蒸一籠,全家都夠吃,皮薄肉餡足!
不管是從包子的體型,還是餡料方面,都和普通的包子不太一樣,體型是比較巨大的,餡料也要更加的鮮美,所以下午花時間蒸一籠,晚上一家人都完全夠吃,所以想要學習這種“巴掌大”包子做法的話,下面就由譚媽媽來為大家分享一下它的詳細做法吧,喜歡包子的朋友...
- 想吃牛排漢堡不用買,在家做,10分鐘能上桌,美味好吃沒負擔
【尼斯牛排堡】素黑椒牛排 1份,時令蔬菜 適量,水煮蛋 1個,醃製青橄欖, 適量橄欖油 適量,羅勒碎 適量,漢堡胚 1個,黃油 適量,沙拉醬 適量,芝士片 1片【製作步驟】準備好食材,將素黑椒牛排取出解凍完全再使用,除了素牛排,還有其他的嘉...
- 紅米K40s和Redmi Note12Pro怎麼選?
京東京享紅包京東紅包購買Redmi K40S 驍龍870 三星E4 AMOLED 120Hz直屏 OIS光學防抖 67W快充¥1999京東購買紅米Note 12Pro顏值質感更好,優勢有:1、螢幕帶高頻調光,更護眼...