1. 程式人生 > >對象初階_繼承

對象初階_繼承

深度優先 可能 fun 統一 pre 根據 一個 參數 object類

繼承

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

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

class ParentClass1: #定義父類
    pass

class ParentClass2: #定義父類
    pass

class SubClass1(ParentClass1): #單繼承,基類是ParentClass1,派生類是SubClass
    pass

class SubClass2(ParentClass1,ParentClass2): #python支持多繼承,用逗號分隔開多個繼承的類
pass

查看繼承

>>> SubClass1.__bases__ #__base__只查看從左到右繼承的第一個子類,__bases__則是查看所有繼承的父類
(<class __main__.ParentClass1>,)
>>> SubClass2.__bases__
(<class __main__.ParentClass1>, <class __main__.ParentClass2>)

提示:如果沒有指定基類,python的類會默認繼承object類,object是所有python類的基類,它提供了一些常見方法(如__str__)的實現。

>>> ParentClass1.__bases__
(<class object>,)
>>> ParentClass2.__bases__
(<class object>,)

繼承與重用性

在開發程序的過程中,如果我們定義了一個類A,然後又想新建立另外一個類B,但是類B的大部分內容與類A的相同時

我們不可能從頭開始寫一個類B,這就用到了類的繼承的概念。

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

派生

類也可以添加自己新的屬性或者在自己這裏重新定義這些屬性(不會影響到父類),需要註意的是,一旦重新定義了自己的屬性且與父類重名,那麽調用新增的屬性時,就以自己為準了。

在子類中,新建的重名的函數屬性,在編輯函數內功能的時候,有可能需要重用父類中重名的那個函數功能,應該是用調用普通函數的方式,即:類名.func(),此時就與調用普通函數無異了,因此即便是self參數也要為其傳值.

在python3中,子類執行父類的方法也可以直接用super方法.

class A:
    def hahaha(self):
        print(A)

class B(A):
    def hahaha(self):
        super().hahaha()
        #super(B,self).hahaha()
        #A.hahaha(self)
        print(B)

a = A()
b = B()
b.hahaha()
super(B,b).hahaha()

幫你了解super
class Animal:
    ‘‘‘
    人和狗都是動物,所以創造一個Animal基類
    ‘‘‘
    def __init__(self, name, aggressivity, life_value):
        self.name = name  # 人和狗都有自己的昵稱;
        self.aggressivity = aggressivity  # 人和狗都有自己的攻擊力;
        self.life_value = life_value  # 人和狗都有自己的生命值;

    def eat(self):
        print(%s is eating%self.name)

class Dog(Animal):
    ‘‘‘
    狗類,繼承Animal類
    ‘‘‘
    def __init__(self,name,breed,aggressivity,life_value):
        super().__init__(name, aggressivity, life_value) #執行父類Animal的init方法
        self.breed = breed  #派生出了新的屬性

    def bite(self, people):
        ‘‘‘
        派生出了新的技能:狗有咬人的技能
        :param people:  
        ‘‘‘
        people.life_value -= self.aggressivity

    def eat(self):
        # Animal.eat(self)
        #super().eat()
        print(from Dog)

class Person(Animal):
    ‘‘‘
    人類,繼承Animal
    ‘‘‘
    def __init__(self,name,aggressivity, life_value,money):
        #Animal.__init__(self, name, aggressivity, life_value)
        #super(Person, self).__init__(name, aggressivity, life_value)
        super().__init__(name,aggressivity, life_value)  #執行父類的init方法
        self.money = money   #派生出了新的屬性

    def attack(self, dog):
        ‘‘‘
        派生出了新的技能:人有攻擊的技能
        :param dog: 
        ‘‘‘
        dog.life_value -= self.aggressivity

    def eat(self):
        #super().eat()
        Animal.eat(self)
        print(from Person)

egg = Person(egon,10,1000,600)
ha2 = Dog(二楞子,哈士奇,10,1000)
print(egg.name)
print(ha2.name)
egg.eat()

通過繼承建立了派生類與基類之間的關系,它是一種‘是‘的關系,比如白馬是馬,人是動物。

當類之間有很多相同的功能,提取這些共同的功能做成基類,用繼承比較好,比如教授是老師

繼承順序

1.python的類可以繼承多個類,Java和c#則只能繼承一個類

2.Python的類如果繼承了多個類,那麽其尋找方法的方式有兩種,分別是:深度優先,廣度優先

  當類是經典類時,多繼承情況下,會按照深度優先方式查找(從左到右一直沿一條路徑走到底再返回的方式遍歷)

  當類是新式類時,多繼承情況下,會按照廣度優先方式查找(從左到右以最短路徑遍歷每個父類)

3.經典類和新式類,從字面上可以看出一個老一個新,新的必然包含更多的功能,也是之後推薦的寫法,基類或者父類繼承了object類,那麽該類便是新式類,否則便是經典類

4.python2中才分經典類和新式類,python3中統一都是新式類

python到底是如何實現繼承的,對於你定義的每一個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表,例如

>>> F.mro() #等同於F.__mro__
[<class __main__.F>, <class __main__.D>, <class __main__.B>, <class __main__.E>, <class __main__.C>, <class __main__.A>, <class object>]
 

為了實現繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。
而這個MRO列表的構造是通過一個C3線性化算法來實現的。我們不去深究這個算法的數學原理,它實際上就是合並所有父類的MRO列表並遵循如下三條準則:
1.子類會先於父類被檢查
2.多個父類會根據它們在列表中的順序被檢查
3.如果對下一個類存在兩個合法的選擇,選擇第一個父類

對象初階_繼承