您現在的位置是:首頁 > 遊戲

類的繼承和多型,簡易的Python面向物件教程

由 CDA資料分析師 發表于 遊戲2022-10-18
簡介假設牧羊犬的叫聲和普通叫聲是不一樣的,我們在子類中覆蓋父類中的方法:class SheepDog(Dog):‘’‘牧羊犬,包括名字,高度,攻擊力和能看護的養的個數’‘’def __init__(self, name, height, pow

說明類的繼承和多型有什麼作用

作者:麥叔

面向物件是所有高階語言(Python,Java,C++等)的基石,是重中之重。

這個文章系列的目的是透過簡單易懂的例子,深入淺出,讓Python學習者牢固的掌握Python面向物件的概念和方法。

本系列包括:

面向物件(1) - 屬性,構造方法,self關鍵詞。

面向物件(2) - 例項方法 (本文)

面向物件(3) - 類屬性和類方法

面向物件(4) - 繼承和多型,以及一個綜合小遊戲案例

類的繼承和多型,簡易的Python面向物件教程

類的繼承,父類,子類

看這張圖:

類的繼承和多型,簡易的Python面向物件教程

上面有一條小狗,代表了普通的狗。

下面有警犬,牧羊犬和寵物犬,他們都是狗。

但他們又有獨特的特點,具有額外的屬性或者技能。

警犬有偵探功能,所以有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()

列印的結果是:

我是牧羊犬,我驕傲!

整合和覆蓋的用處舉例

類的繼承和對父類方法的覆蓋在程式碼設計中很有用。假設有個程式的介面是這樣的:

類的繼承和多型,簡易的Python面向物件教程

按鈕就是一個類,比如叫做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怎麼選?

    紅米K40s和Redmi Note12Pro怎麼選?京東京享紅包京東紅包購買Redmi K40S 驍龍870 三星E4 AMOLED 120Hz直屏 OIS光學防抖 67W快充¥1999京東購買紅米Note 12Pro顏值質感更好,優勢有:1、螢幕帶高頻調光,更護眼...