day24:繼承

1,複習1python

# 面向對象編程
# 思想:角色的抽象,建立類,建立角色(實例化),操做這些示例
# 面向對象的關鍵字

class 類名:
    靜態屬性 = 'aaa'
    def __init__(self):pass

類名.靜態屬性 # --儲存在類的命名空間裏
對象 = 類名() # 實例化:創造了一個self對象,執行init方法,返回self對象給外部
# 對象.屬性
# 對象.方法 綁定方法,方法和對象綁定到了一塊兒 # 類名.方法(對象)
# 對象可使用靜態變量?True
# 類可使用對象裏的屬性嗎?False

2,複習2面試

# 組合
# 一個類的對象是另一個類的屬性
# 什麼有什麼的關係

class A:
    def __init__(self):
        self.name = 'egon'

class B:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day

b = B(18,1,17)
a = A()
a.birth = b
print(b.year)  # 18
print(a.birth.year) # 18

3,面向對象的三大特性:繼承,多態和封裝,很是很是重要的,計算機領域的三大特性算法

什麼是繼承:繼承是一種建立新類的方式,在Python中,新建的類能夠繼承一個或多個父類,父類又可稱爲基類或超類,新建的類稱爲派生類或子類編程

class A:pass # 父類,基類,超類
class B:pass # 父類,基類,超類
class A_son(A,B):pass # 子類,派生類
class AB_son(A):pass # 子類,派生類

# 一個類 能夠被多個類繼承
# 一個類 能夠繼承多個父類 ----這個只有Python裏面纔有

print(A_son.__bases__)
# (<class '__main__.A'>, <class '__main__.B'>)
print(AB_son.__bases__)
# (<class '__main__.A'>,)
print(A.__bases__) 
# (<class 'object'>,)

4,類裏面,剛開始加載類的時候,就從上到下把類裏面的名字加載進去了,加載進去後才能夠用類名.靜態屬性。佔內存的也只是裏面的變量名字而已設計模式

5,object在類食物鏈的頂端, python3裏面沒有繼承父類,默認繼承object,這種累叫作新式類,object類是一個很是強大的類,裏面實現了不少不少的內容,object裏面有不少雙下方法網絡

6,一般的繼承都是咱們本身寫的類,可是到網絡編程的時候,咱們會接觸到繼承Python裏面已經存在的類,例如str等python2.7

7,抽象,抽取相似或者比較像的部分,抽象最主要的做用是劃分類別,能夠隔離關注點,下降複雜度spa

8,類和類的關係叫作繼承,類和對象的關係叫作實例化。設計

 

class Animal:
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp

class Dog(Animal):
    def bite(self,person):
        person.hp -= self.aggr

class Person(Animal):
    pass

jin = Dog('bossjin',200,500)  # 子類沒有__init__方法,會去調用父類的雙下init方法
print(jin.name)

 

9,子類和父類都有的方法,會優先調用誰的呢?這是一道面試題,傳誰的self就運行誰的方法。code

class Animal:
    def __init__(self):
        print("執行Animal.__init__")
        self.func()

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

    def drinking(self):
        print("%s dringking"%self.name)

    def func(self):
        print("Animal.func")

class Dog(Animal):
    def guard(self):  
        print('guarding')

    def func(self):
        print('Dog.func')

dog = Dog()  # 這兒調用的是Dog類裏面的func.由於self傳得是dog

運行結果:
執行Animal.__init__
Dog.func

10,對於下面的問題怎麼解決呢?

class Animal:
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp

class Dog(Animal):
    def __init__(self,name,aggr,hp,kind):
        self.kind = kind

    def bite(self,person):
        person.hp -= self.aggr


jin = Dog('bossjin',200,500,'teddy')
print(jin.name)  # AttributeError: 'Dog' object has no attribute 'name'
# 錯誤緣由,本身有了init就不會再去運行父類的init方法,

11,派生屬性

class Animal:
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp

class Dog(Animal):
    def __init__(self,name,aggr,hp,kind):
        Animal.__init__(self,name,aggr,hp) # 這個地方咱們不只完成了繼承,還完成了派生,也就是一個派生屬性,新添加的屬性
        self.kind = kind

    def bite(self,person):
        person.hp -= self.aggr


jin = Dog('bossjin',200,500,'teddy')
print(jin.name) # bossjin

12,除了有派生屬性,還有派生方法,父類沒有子類有的就是派生方法;父類中沒有的屬性,在子類中出現,叫作派生屬性;父類中沒有的方法,在子類中出現,叫作派生方法。

只要是子類的對象調用,子類中有的名字,必定用子類的,子類中沒有才找父類的,若是父類也沒有,報錯;若是父類子類都有,用子類的;若是還想用父類的,單獨調用父類的,須要本身傳self參數。

13,既想實現新的功能,也想用父類的功能,須要單獨調用父類的

class Animal:
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp

    def eat(self):
        print("吃藥回血")
        self.hp += 100

class Dog(Animal):
    def __init__(self,name,aggr,hp,kind):
        Animal.__init__(self,name,aggr,hp) # 這個地方咱們不只完成了繼承,還完成了派生,也就是一個派生屬性,新添加的屬性
        self.kind = kind # 派生屬性

    def eat(self):
        Animal.eat(self)  # 若是既想實現新的功能也想使用父類本來的功能,還須要在子類中再調用父類
        self.teeth = 2

    def bite(self,person):  # 派生方法
        person.hp -= self.aggr


jin = Dog('bossjin',200,500,'teddy')
jin.eat()
print(jin.teeth)

14,另一個調用父類方法的Python3中的用法,super,類內和類外均可以用,內部能夠不傳參,外部必傳

class Animal:
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp

    def eat(self):
        print("吃藥回血")
        self.hp += 100

class Dog(Animal):
    def __init__(self,name,aggr,hp,kind):
        super().__init__(name,aggr,hp)
        # self 不須要單獨傳了,super()意思是找個人父類,而後就能夠調用父類的init了
        # 這個地方省略了兩個參數 Dog類和self對象兩個參數
        # super關鍵字只要新式類中有,不是Python3,Python中全部的類都是新式類,Python2中兩種類共存
        # super還能夠再類外面用
        self.kind = kind

    def eat(self):
        Animal.eat(self)
        self.teeth = 2
        print('son class')

    def bite(self,person):
        person.hp -= self.aggr


jin = Dog('bossjin',200,500,'teddy')
jin.eat()
print(jin.teeth)
super(Dog,jin).eat() # 這兒調用的是父類的eat方法。

15,子類中調用父類方法兩種:父類名.方法名 須要本身傳self參數,super().方法名 類內不須要本身傳self

16,正常的代碼中 單繼承 ==減小了代碼的重複,繼承表達了一種子類是父類的關係,提到組合和繼承必定是兩個類以上的,看是「是」的關係仍是「有」的關係。例如:老師有生日,狗是動物

17,工做中用的通常都是單繼承,多繼承通常就是設計模式,或者面試中用到,多繼承的繼承順序問題

class A:
    def func(self):print('A')
class B:
    def func(self):print('B')
class C:
    def func(self): print('C')

class D(A,B,C):
    def func(self): print('D')


# 調用順序
print(D.mro())
# [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>]

18,鑽石繼承問題:

class A:
    def func(self):print('A')
class B(A):
    def func(self):print('B')
class C(A):
    def func(self): print('C')

class D(B,C):
    def func(self): print('D')


# 調用順序
print(D.mro())
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

19,Python3裏面全部的新式類都是採用廣度優先的方式,漏斗,若是後面有機會找到爺爺類,那麼就能夠廣度優先找

# 漏斗
class A:
    def func(self):print('A')
class B(A):
    def func(self):print('B')
class E:
    def func(self):print('E')
class C(E):
    def func(self): print('C')

class D(B,C):
    def func(self): print('D')


# 調用順序
print(D.mro())
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>]

20,小烏龜問題,就是一個六邊形,

# 小烏龜
class F:
    def func(self):print('F')

class A(F):
    def func(self):print('A')
class B(A):
    def func(self):print('B')
class E(F):
    def func(self):print('E')
class C(E):
    def func(self): print('C')

class D(B,C):
    def func(self): print('D')


# 調用順序
print(D.mro())
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>]

21,get 一個算法,method resolution order mro,新式類,廣度優先;經典類是深度優先(一條道走到黑,只要能到就一直走這條道,走到頭就走另一條),繼承object的類纔是新式類,經典類若是直接建立一個類在2.7中就是經典類,深度優先。

22,多繼承中,咱們子類的對象調用一個方法,默認是就近原則,經典類中,深度優先,新式類中,廣度優先,python2.7新式類和經典類共存,新式類要繼承object,python3中只有新式類,默認繼承object,經典類和新式類有一個區別super,mro方法只在新式類中存在

23,super的本質,單繼承裏面永遠是父類,只有多繼承纔會出現同級的super。

class A:
    def func(self):print('A')


class B(A):

    def func(self):
        super().func()
        print('B')

class C(A):

    def func(self):
        super().func()
        print('C')

class D(B,C):

    def func(self):
        super().func()
        print('D')

d = D()
d.func()

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

# A
# C
# B
# D

# super的本質,不是直接找父類,而是根據調用者的節點位置的廣度優先順序來的
相關文章
相關標籤/搜索