熱線電話:13121318867

登錄
首頁大數據時代類的繼承和多態,簡易的Python面向對象教程
類的繼承和多態,簡易的Python面向對象教程
2021-03-12
收藏

來源:麥叔編程

作者:麥叔

面向對象是所有高級語言(Python,Java,C++等)的基石,是重中之重。

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

本系列包括:

  • 面向對象(1) - 屬性,構造方法,self關鍵詞。
  • 面向對象(2) - 實例方法 (本文)
  • 面向對象(3) - 類屬性和類方法
  • 面向對象(4) - 繼承和多態,以及一個綜合小游戲案例
類的繼承和多態,簡易的Python面向對象教程

類的繼承,父類,子類

看這張圖:

類的繼承和多態,簡易的Python面向對象教程
  1. 上面有一條小狗,代表了普通的狗。
  2. 下面有警犬,牧羊犬和寵物犬,他們都是狗。
  3. 但他們又有獨特的特點,具有額外的屬性或者技能。
  4. 警犬有偵探功能,所以有detect()方法,有額外的屬性ability,表示它的偵探能力等級。
  5. 牧羊犬有保護養的功能,所以有protect()方法,有額外的num_of_sheeps表示它可以保護幾只羊。
  6. 寵物犬有唱歌的功能,所以有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()是一個函數,是有括號的。值得注意的是,使用self可以訪問父類的屬性和方法,因為父類的就是自己的。在構造函數中我們使用super()來調用父類的構造函數是因為子類和父類都有__init__方法,如果不適用super()就會調用自己的__init__方法,這種情況下需要用super)()來明確指定要訪問父類的方法。
  4. 第二行添加了牧羊犬的獨特屬性num_of_sheeps。這樣牧羊犬有4個屬性,其中3個屬性是繼承自父類的,一個是自己獨有的。

使用子類

子類的使用和父類是一樣的:

  1. 調用構造函數創建實例。
  2. 通過變量名訪問屬性。
  3. 通過變量名調用方法。注意bark()是父類的函數,子類可以直接使用。
sd1 = SheepDog('大黃'678810)
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(510)
  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(813)
  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)

數據分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數據分析師資訊
更多

OK
客服在線
立即咨詢
日韩人妻系列无码专区视频,先锋高清无码,无码免费视欧非,国精产品一区一区三区无码
客服在線
立即咨詢