PYTHON3中 類的繼承


繼承

1:什么是繼承

繼承是一種創建新類的方式,在python中,新建的類可以繼承一個或多個父類,也就是說在python中支持一個兒子繼承多個爹。

新建的類成為子類或者派生類。

父類又可以成為基類或者超類。

子類會遺傳父類的屬性。

2:為什么要用繼承

減少代碼冗余(也就是重復寫代碼)。

3:怎么用繼承:

我們定義兩個類;
class parenclass1:
        pass

class parenclass2:
        pass


在定義兩個類:

class subclass1:

    pass

class subclass2:
    pass

我想讓 :
class parenclass1:      作為    class  subclass1:     的父類。   
    pass                            pass


應該這樣用: class subclass1( parenclass1): 這就表示subclass1是子類,parenclass 是subclass1 的父類 pass
兩個父類的話怎么表達呢?如下:
class subclass2(parenclass1,parenclass2): pass 這就表示subclass2的父類是parenclass1,parenclass2 這兩個

 

想要查看子類的父類 應該怎樣查看呢: 用__bases__  如下:

class ParentClass1:
    pass

class ParentClass2:
    pass

class Subclass1(ParentClass1):
    pass

class Subclass2(ParentClass1,ParentClass2):
    pass


print(Subclass1.__bases__) 
#打印結果:(<class '__main__.ParentClass1'>,)

print(Subclass2.__bases__)
#打印結果:
(<class '__main__.ParentClass1'>, 
 <class '__main__.ParentClass2'>)

經典類與新式類

1、只有在python2中才分新式類和經典類,python3中統一都是新式類
2、在python2中 沒有顯示繼承的object類的類,以及該類的子類都是經典類
3、在python2中,顯示的聲明繼承object的類,以及該類的子類都是新式類
4、在python3中,無論是否繼承object,都默認 繼承object,即python3中所有類均為新式類

至於經典類 與新式類的區別,后面會有討論。

提示:如果沒有指定基類, python的類會默認繼承object類, object是所有python類的基類。

 

二、繼承與抽象

繼承描述的是子類與父類之間的關系,是一種什么的關系呢? 要找出這種關系, 必須先抽象在繼承。

抽象即抽取類似或者說比較像的部分。

抽象分成兩個層次:

1.將奧巴馬和梅西這倆對象比較像的部分抽取成類; 

2.將人,豬,狗這三個類比較像的部分抽取成父類。

抽象最主要的作用是划分類別(可以隔離關注點,降低復雜度)

 

繼承:是基於抽象的結果,通過編程語言去實現它,肯定是先經歷抽象合格過程, 才能通過繼承的方式去表達抽象的結構。

抽象只是分析和設計的過程,一個動作或者說一種技巧,通過抽象可以得到類

 

 例如:我們寫一個老男孩的老師與學生的類,若是不涉及到繼承的話  我們正常是這樣寫

class OldboyTeacher:
    school = 'oldboy'

    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def change_score(self):
        print('teacher %s is changing score ' %self.name)

class Oldboystudent:
    school = 'oldboy’
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def choose(self):
        print('student %s choose course' %self.name)

tea1 = OldboyTeacher('egon', 18, 'male') #OldboyTeacher.__init__(...)
stu1=Oldboystudent('alex',73,'female')

print(tea1.name,tea1.age,tea1.sex) # egon 18 male

print(stu1.name) #alex

但是我們經過分析 發現里面里面有許多重復代碼, 這時我們可以用到類的繼承來寫了。如下:

class OldboyPeople:
    school ='oldboy'

    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

class Oldboyteacher(OldboyPeople):
    def change_score(self):
        print('teacher %s is changing score ' %self.name)
class Oldboystudent(OldboyPeople): def choose(self): print('student %s choose course'%self.name) tea1 = Oldboyteacher('egon', 18, 'male') stu1=Oldboystudent('alex',73,'female')
print(tea1.name,tea1.age,tea1.sex)#egon
18 male print(stu1.name) #alex

 三、基於繼承在看屬性查找

我們先看一個列子

class Foo:
    def f1(self):
        print('Foo.f1')

    def f2(self): #self=obj
        print('Foo.f2')    #在父類中找到發 f2屬性,第3步打印這一行
        self.f1() #obj.f1()  第4步再去掉用self的f1屬性

class Bar(Foo):
    def f1(self):#第五步, 在回到object自身的名稱空間找f1屬性,找到后調用
        print('Bar.f1') #第6步 執行

obj=Bar() #第一步 :類的實例化, 先得到一個空對象,

obj.f2()  #第2步:空對象調用f2屬性 在自身尋找f2屬性, 沒有找到就去父類中尋找

#結果

Foo.f2
Bar.f1

注意子類的屬性查找,一定是優先查找子類自己本身的屬性與特征, 在本身沒有的情況下 在去父類中查找。

四、派生

派生:子類定義自己新的屬性,如果與父類同名,以子類自己的為准。

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def f1(self):
        print('爹的f1')
class OldboyTeacher(OldboyPeople):
    def change_score(self):
        print('teacher %s is changing score' %self.name)

    def f1(self):
        print('兒子的f1')

tea1 = OldboyTeacher('egon', 18, 'male')
tea1.f1()

#調用顯示:兒子的f1
# 父類和子類中都有f1, 優先調用自己的屬性,所以結果調用的是兒子的f1

五、在子類中派生出的新方法重用父類的功能

拿上一案例來舉例 在oldboyteacher 這個類中要添加薪水與級別。 然后調用。 有兩種方式。

方式一:指名道姓的調用(與繼承沒有什么關系)

class OldboyPeople:
    school ='oldboy'

    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def tell_info(self):
        print(
            '''
            ====個人信息====
           姓名:%s
           年齡:%s
           性別:%s
            '''%(self.name,self.age,self.sex))

class OldboyTeacher(OldboyPeople):

    def __init__(self,name,age,sex,level,salary):
        OldboyPeople.__init__(self,name,age,sex)  #在這里指明道姓來調用這一個函數里的屬性

        self.level =level
        self.salary=salary

    def tell_info(self):
        OldboyPeople.tell_info(self)   #指名道姓的來調用這個函數里的屬性
        print("""
        等級:%s
        薪資:%s
        """ %(self.level,self.salary))

tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1)
print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary)


tea1.tell_info()

#打印結果:
egon 18 male 9 3.1

            ====個人信息====
           姓名:egon
           年齡:18
           性別:male
            

        等級:9
        薪資:3.1

方法二、

用super()調用(嚴格依賴於繼承)

super() 的返回值是一個特殊的對象,該對象專門用來調用父類中的屬性, 一般在python2中,需要super(自己的類名,self),  而python3中,括號里面一般不填類名

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def tell_info(self):
        print("""
        ===========個人信息==========
        姓名:%s
        年齡:%s
        性別:%s
        """ %(self.name,self.age,self.sex))


class OldboyTeacher(OldboyPeople):

    def __init__(self, name, age, sex, level, salary):
        super().__init__(name,age,sex)

        self.level = level
        self.salary = salary

    def tell_info(self):
        super().tell_info()
        print("""
        等級:%s
        薪資:%s
        """ %(self.level,self.salary))

tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1)
print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary)
tea1.tell_info()

#調用結果:
egon 18 male 9 3.1

        ===========個人信息==========
        姓名:egon
        年齡:18
        性別:male
        

        等級:9
        薪資:3.1
        

 

六:經典類 與新式類

1新式類:

繼承object的類,以及該類的子類,都是新式類

在python3中,如果一個類沒有指定繼承的父類,默認就繼承object

所以說在python3中所有的類都是新式類

 

2經典類:(只有在python2才區分經典類和新式類):

沒有繼承object的類,以及該類的子類 都是經典類

1 經典類:深度優先

2 新式類:廣度優先

如果繼承關系為非菱形結果嗎則會按照先找B 這一條分支,然后在找c這一條分支,最后找D這一條分支的順序,直到找到我們想要的屬性

 

當繼承關系為菱形結構時

經典類查找順序:

 

若是在A 類里自己沒找到, 則會先去B類里去找, B類里沒找到,就會在E類里找, 然后在G類里找,

G類里沒找到 會去C 類里找, 然后去F 類里找,最后去D 類里找。

 

新式類查找順序: 

按照圖中1 ,2 , 3, 4,5,6的順序查找, 這個為廣度優先的查找方式

 

七:  super()依賴繼承

super()會嚴格按照mro列表從當前查找到的位置繼續往后查找

class A:
    def test(self):
        print('A.test') #2 執行這一步 打印
        super().f1 #3 然后在調用父類里的f1,   根據C.mro里的查找順序執行到A 往后繼續執行到B里去查找

class B:
    def f1(self): #4找到f1, 執行
        print('from B')  #5打印

class C(A,B):
    pass

c=C()
print(C.mro())  #調用屬性的順序  [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

c.test() #1:C里沒有 ,去A里調用

#打印結果

A.test

from B

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

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



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