python 類的三大特性--繼承


繼承                                                                                                                

繼承指的是類與類之間的關系,是一種什么“是”什么的關系,繼承的功能之一就是用來解決代碼重用問題,

繼承是一種創建新類的方式,在python中新建的類可以繼承一個或多個父類,父類可稱為基類或者超類,新建的類稱為派生類或子類。

python中類的繼承分為:單繼承和多繼承

class Biology:                # 定義一個父類
    pass


class Animal:                 # 定義一個父類
    pass


class Person(Biology):        # 單繼承,基類是Biology, 派生類是person
    pass


class Dog(Biology, Animal):   # 多繼承,用逗號隔開多個基類
    pass

查看繼承:

# 可通過類名.__bases__查看所有繼承的父類,類名.__base__只查看從左到右繼承的第一個父類
print(Dog.__base__)
# <class '__main__.Biology'>
print(Dog.__bases__)
# (<class '__main__.Biology'>, <class '__main__.Animal'>)

經典類和新式類:

1.只有在python2中才分新式類和經典類,python3中統一都是新式類

2.在python2中,沒有聲明繼承object類的類,以及該類的子類,都是經典類

3.在python2中,聲明繼承object的類,以及該類的子類,都是新式類

4.在python3中,無論是否繼承object,都默認繼承object,即python3中所有類均為新式類

繼承與抽象:

抽象即抽取類似或比較像的部分。
抽象分為兩個層次:
1.把多個對象中比較像的部門抽取成類
2.把多個類中比較像的部門抽取成父類
抽象最主要的作用是划分類別(可以隔離關注點,降低復雜度)
繼承:是基於抽象的結果,通過編程語言去實現它,肯定是先經歷抽象這個過程,才能通過繼承的方式去表達出抽象的結構
抽象只是分析和設計的過程中,一個動作或者說一種技巧,通過抽象可以得到類

繼承與重用性

class Hero(object):  # 英雄的類
    def __init__(self, name, camp, money, life_value, aggressivity,
                 defensive):  # 類的屬性包括:英雄的名字,陣營,資產,生命值,攻擊力,防御力
        self.name = name
        self.camp = camp
        self.money = money
        self.life_value = life_value
        self.aggressivity = aggressivity
        self.defensive = defensive

    def attack(self, enemy):  # 類的技能,英雄具有攻擊技能
        enemy.life_value -= self.aggressivity
      
        
class Garen(Hero):                  # Garen類繼承Hero類
    pass


class Riven(Hero):                 # Riven類繼承Hero類
    pass


garen1 = Garen("德瑪西亞之力", "德瑪西亞", 1000, 300, 60, 40)      # 實例化Garen類時,Hero類中定義的屬性直接使用
riven1 = Riven("銳萌萌", "諾克薩斯", 1000, 280, 70, 30)
garen1.attack(riven1)                                          # Garen類實力話的對象可以直接使用Hero類中定義的方法
print(garen1.life_value)
print(riven1.life_value)

通過繼承的方式新建類B,讓B繼承A,B會‘遺傳’A的所有屬性(數據屬性和函數屬性),實現代碼重用。

派生

class Garen(Hero):  # Garen類繼承Hero類
    def attack(self, enemy):            # 子類可以重新定義攻擊技能,不會改變父類的攻擊方法
        enemy.life_value -= (self.aggressivity - enemy.defensive)
        
    def life_reply(self):               # 子類可以新加一個生命恢復技能
        self.life_value += 20

屬性查找順序 

先從自己內部找,然后再去類里找,最后再去父類中找。

父類中查找的順序

經典類:按繼承的類的順序從左到右深度優先

 

新式類:按繼承的類的順序從左到右廣度優先

對於你定義的每一個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表,為了實現繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。而這個MRO列表的構造是通過一個C3線性化算法來實現的。

 

class A(object):
    def test(self):
        print("from a")
class B(A):
    pass
    # def test(self):
    #     print("from b")

class C(A):
    pass
    # def test(self):
    #     print("from c")
class D(B):
    pass
    # def test(self):
    #     print("from d")
class E(C):
    pass
    # def test(self):
    #     print("from e")
class F(A):
    pass
    # def test(self):
    #     print("from f")
class H(D,E,F):
    pass
h1 = H()
h1.test()            # from a
print(H.__mro__)   #只有新式才有這個屬性可以查看線性列表,經典類沒有這個屬性
# (<class '__main__.H'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.A'>, <class 'object'>)

子類里調用父類的方法

在子類派生出的新方法中,往往需要重用父類的方法,我們有兩種方式實現

一、指名道姓,即父類名.父類方法()

二、super()

class Hero(object):  # 英雄的類
    def __init__(self, name, camp, money, life_value, aggressivity,
                 defensive):  # 類的屬性包括:英雄的名字,陣營,資產,生命值,攻擊力,防御力
        self.name = name
        self.camp = camp
        self.money = money
        self.life_value = life_value
        self.aggressivity = aggressivity
        self.defensive = defensive
    
    def attack(self, enemy):  # 類的技能,英雄具有攻擊技能
        enemy.life_value -= self.aggressivity


class Garen(Hero):  # Garen類繼承Hero類
    def __init__(self, name, camp, money, life_value, aggressivity, defensive, sex):
        # Hero.__init__(self, name, camp, money, life_value, aggressivity, defensive)  # 指名道姓
        # super(Garen, self).__init__(name, camp, money, life_value, aggressivity, defensive)     # python2
        super().__init__(name, camp, money, life_value, aggressivity, defensive) # python3中 super() = super(Garen, self)
        self.sex = sex
        
    def attack(self, enemy):  # 子類可以重新定義攻擊技能,不會改變父類的攻擊方法
        enemy.life_value -= (self.aggressivity - enemy.defensive)
    
    def life_reply(self):  # 子類可以新加一個生命恢復技能
        self.life_value += 20


class Riven(Hero):  # Riven類繼承Hero類
    pass

garen1 = Garen("德瑪西亞之力", "德瑪西亞", 1000, 300, 60, 40, "man")
riven1 = Riven("銳萌萌", "諾克薩斯", 1000, 280, 70, 30)
garen1.attack(riven1)  # Garen類實力話的對象可以直接使用Hero類中定義的方法
print(garen1.life_value)
print(riven1.life_value)

兩種方式的區別:方式一時跟繼承沒有關系的,而方式二的super()是依賴與繼承的,並且即使沒有直接繼承關系,super()仍然會按照mro繼續往后查找

#A沒有繼承B,但是A內super會基於C.mro()繼續往后找
class A:
    def test(self):
        super().test()
class B:
    def test(self):
        print('from B')
class C(A,B):
    pass

c=C()
c.test() #打印結果:from B


print(C.mro())
#[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

組合                                                                                                                                        

組合指的是類與類之間的關系,是一種什么“有”什么的關系,在一個類中以另一個類的對象作為數據屬性,稱為類的組合

class Arms:  # 定義一個武器類
    def __init__(self, aggressivity):  # 定義武器攻擊力屬性
        self.aggressivity = aggressivity


class Hero:  # 定義一個英雄的類
    role = "hero"  # 定義一個公同屬性角色

    def __init__(self, camp, life_value, aggressivity, defensive,
                 arm=0):  # 定義一個自定義值的屬性函數 屬性包括生命值,攻擊力,防御,和武器屬性,默認是0,傳入武器后改變
        self.camp = camp
        self.life_value = life_value
        self.aggressivity = aggressivity
        self.defensive = defensive
        self.arm = []             # 裝備的武器列表
        
    def attack(self, target):  # 攻擊技能
        aggressvity = self.aggressivity
        if self.arm:    # 判斷是否裝備了武器
            for i in self.arm:
                aggressvity += i.aggressivity   # 將武器的攻擊力加上

        target.life_value -= (aggressvity - target.defensive)


garen = Hero("Demarcia", 100, 60, 30)  # 實例化一個蓋倫對象,並傳入英雄的生命值,攻擊,防御,武器
rivan = Hero("xx", 90, 70, 20)  # 實例化一個銳雯對象,並傳入英雄的生命值,攻擊,防御,武器
big_sword = Arms(60)    # 實例化武器的類,生成一個名叫大劍的武器
garen.arm.append(big_sword)  # 給蓋倫裝備裝大劍
garen.attack(rivan)  # 蓋倫攻擊銳雯一次
print(rivan.life_value)

總結:

當類之間有顯著不同,並且較小的類是較大的類所需要的組件時,用組合比較好

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM