物件導向之繼承

來源:互聯網
上載者:User

標籤:工作   分享圖片   abc   優點   字串   自己   深度   ssr   根據   

標籤(空格分隔): 繼承

什麼是繼承:
繼承是指類與類之間的關係,是一種什麼“是”什麼的關係,繼承的功能之一就是用來解決代買重用問題,繼承是一種建立新類的方式,在python中,建立的類是可以繼承多個父類,父類又可以成為基類或者超類,建立的類稱為衍生類別或者子類;

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


派生

派生:是在繼承中,子類有自己的特點,有自己的東西,即使是同一個方法,子類也可以有自己的特色;

繼承的實現原理:


繼承的原則:
深度優先,廣度優先;

子類繼承後,對方法重寫


如果子類中有的方法,並且重寫了,在執行個體化的時候,還是先用子類的方法,如果子類找不到就用,繼承來的;

  • 繼承是指的類與類之間的關係;

例如:選課系統:
選課系統裡面:有老師,學生,這些可以定義為類;

class Teacher:    school ='luffycity'    def __init__(self,name,age,sex,level,salary):        self.name=name        self.age=age        self.sex=sex        self.level=level        self.salary=salary            def teach(self):        print('%s is teaching '%self.name)class Student:    school ='luffycity'    def __init__(self,name,age,sex,class_time):        self.name=name        self.age=age        self.sex=sex        self.class_time=class_time    def learn(self):        print(%s is learning '%self.name)

上述代碼會發現我們這裡面有很多的重複代碼,會有很多的重複的代碼,所以針對類之間的重複的代碼,我們可以使用繼承,把相同的功能,封裝,然後繼承,如上述我們可以,定義一個people,然後老師和學生繼承就好了;

so:如下代碼;

class People:    school = 'luffycity'    def __init__(self,name,age,sex):        self.name=name        self.age=age        self.sex=sex        class Teacher(People):    def __init__(self,name,age,sex,level,salary):        super().__init__(name,age,sex)        self.level=level        self.salary=salary            def teach(self):        print('%s is teaching '%self.name)class Student:    school ='luffycity'    def __init__(self,name,age,sex,class_time):        super().__init__(name,age,sex)        self.class_time=class_time    def learn(self):        print(%s is learning '%self.name)    teacher1 = Teacher('www',18,'male',10,3000)student1=Student('zhangsan',28,'feamal','18:34:45')

如上的代碼如果:老師有課程,課程周期,課程價格的屬性的時候,怎麼辦呢,代碼如下:我們可以給__init__增加屬性

class People:    school = 'luffycity'    def __init__(self,name,age,sex):        self.name=name        self.age=age        self.sex=sex        class Teacher(People):    def __init__(self,name,age,sex,level,salary,course_name,course_price,course_period):        super().__init__(name,age,sex)        self.level=level        self.salary=salary        self.course_name=course_name        self.course_price=course_price        self.course_period=course_period            def teach(self):        print('%s is teaching '%self.name)class Student:    school ='luffycity'    def __init__(self,name,age,sex,class_time):        super().__init__(name,age,sex)        self.class_time=class_time    def learn(self):        print(%s is learning '%self.name)    teacher1 = Teacher('www',18,'male',10,3000,'python',3000,'dkkd')teacher1 = Teacher('aaa',18,'male',10,3000,'python',3000,'dkkd')

如上述的代碼會有很多,關於課程的資訊,寫了很多重複的代碼;

這樣我們可以把課程單獨的定義一個類:

class People:    school = 'luffycity'    def __init__(self,name,age,sex):        self.name=name        self.age=age        self.sex=sex        class Teacher(People):    def __init__(self,name,age,sex,level,salary,):        super().__init__(name,age,sex)        self.level=level        self.salary=salary                    def teach(self):        print('%s is teaching '%self.name)class Student:    school ='luffycity'    def __init__(self,name,age,sex,class_time):        super().__init__(name,age,sex)        self.class_time=class_time    def learn(self):        print(%s is learning '%self.name)        class Course:    def __init__(self,course_name,course_price,course_period)        self.course_name =course_name        self.course_price=course_price        self.course_period =course_period    def tell_info(self):        print('課程名稱<%s> 課程價格<%s> 可傳給你周期<%s>'%(self.course_name,self.course_price,self.course))teacher1.course.tell_info()

這就是組合

teacher1 =Teacher(‘alex‘,18,‘male‘,10,3000,)
teacher1.course=‘python‘
teacher2.course=‘python‘

```;

多態

多態指的是一類事物有多種形態,比如動物有多種形態:人,狗,豬

import abcclass Animal(metaclass=abc.ABCMeta): #同一類事物:動物    @abc.abstractmethod    def talk(self):        passclass People(Animal): #動物的形態之一:人    def talk(self):        print('say hello')class Dog(Animal): #動物的形態之二:狗    def talk(self):        print('say wangwang')class Pig(Animal): #動物的形態之三:豬    def talk(self):        print('say aoao')

研究多態,就是研究同一種事物多種狀態,

多態性:指的是可以在不考慮執行個體的類型的情況下,而直接使用對象,
peo1=People()
dog1=Dog()
pig1=Pig()

peo1.talk()
dog1.talk()
pig1.talk()

以上的多態性,指的是動態多態性,多態性,不用考慮具體的執行個體類型,就可以直接用;

def func(animal):    animal.talk()func(peo1)func(pig1)func(dog1)

二 為什麼要用多態性(多態性的好處)

其實大家從上面多態性的例子可以看出,我們並沒有增加什麼新的知識,也就是說python本身就是支援多態性的,這麼做的好處是什麼呢?

1.增加了程式的靈活性

  以不變應萬變,不論對象千變萬化,使用者都是同一種形式去調用,如func(animal)

2.增加了程式額可擴充性

 通過繼承animal類建立了一個新的類,使用者無需更改自己的代碼,還是用func(animal)去調用  
 
 Python崇尚鴨子類型,即‘如果看起來像、叫聲像而且走起路來像鴨子,那麼它就是鴨子’

python程式員通常根據這種行為來編寫程式。例如,如果想編寫現有對象的自訂版本,可以繼承該對象

也可以建立一個外觀和行為像,但與它無任何關係的全新對象,後者通常用於儲存程式組件的松耦合度。

例1:利用標準庫中定義的各種‘與檔案類似’的對象,儘管這些對象的工作方式像檔案,但他們沒有繼承內建檔案對象的方法

#二者都像鴨子,二者看起來都像檔案,因而就可以當檔案一樣去用class TxtFile:    def read(self):        pass    def write(self):        passclass DiskFile:    def read(self):        pass    def write(self):        pass

例2:序列類型有多種形態:字串,列表,元組,但他們直接沒有直接的繼承關係

#str,list,tuple都是序列類型s=str('hello')l=list([1,2,3])t=tuple((4,5,6))#我們可以在不考慮三者類型的前提下使用s,l,ts.__len__()l.__len__()t.__len__()len(s)len(l)len(t)
封裝

從封裝本身的意思去理解,封裝就好像是拿來一個麻袋,把小貓,小狗,小王八,還有alex一起裝進麻袋,然後把麻袋封上口子。照這種邏輯看,封裝=‘隱藏’,這種理解是相當片面的

如何?隱藏:
  • 在python中用雙底線開頭的方式將屬性隱藏起來(設定成私人的)
class A:    __N=0 #類的資料屬性就應該是共用的,但是文法上是可以把類的資料屬性設定成私人的如__N,會變形為_A__N    def __init__(self):        self.__X=10 #變形為self._A__X    def __foo(self): #變形為_A__foo        print('from A')    def bar(self):        self.__foo()        print('from bar')        #只有在類內部才可以通過__foo的形式訪問到.#A._A__N是可以訪問到的,即這種操作並不是嚴格意義上的限制外部存取,僅僅只是一種文法意義上的變形

注意:以上的__N是隱藏的屬性,注意python裡面,以__開頭的是隱藏,以__開頭,__結尾是python內建的屬性和方法,這點大家切記!,不要搞混了;

變形的特點:
1.外部無法直接存取obj.__attrName
2.在類的內部可不可以obj.__AttriName,答案是可以的
3.子類無法覆蓋父類__開頭的屬性;(因為他兩個不是一個名字)

封裝的意義

1.封裝資料屬性:明確的區分內外

class People:    def __init__(self,name,age):        self.__name =name        self.__age=agep=People('egon',18)P.__name

資料屬性分裝之後外部是不可以訪問的,在內部是可以,但是外部可以間接的訪問,我們可以在類的內部開一個介面,通過介面訪問,

class People:    def __init__(self,name,age):        self.__name =name        self.__age=age    def tell_info(self):        print('Name:<%s> Age:<%s>' %(self.__name , self.__age))        p=People('egon',18)p.tell_info()

如上述的代碼,我們把隱藏的屬性放在:tell_info()中,外部的執行個體化對象,要想訪問,就通過執行個體對象.tell_info()這種方法,這就要通過介面方法來訪問的,方便快捷;

2.同樣上述的代碼,使用者不能對name,age直接進行修改了,我們需要開一個介面可以供使用者進行修改;

class People:    def __init__(self,name,age):        self.__name =name        self.__age=age    def tell_info(self):        print('Name:<%s> Age:<%s>' %(self.__name , self.__age))    def set_info(self,name,age):        if not isinstance(name,str):            print("名字是字串")            return        if not isinstance(age,str):            print("年齡是字串")            return        self.__name =name        self.__age=age                p=People('egon',18)p.tell_info()P.set_info('EGON',38)#這裡我們用的開的介面來修改的P.set_info('egon','12')
  • 這就是我們資料屬性的封裝,明確的區分內外,控制外部對影藏屬性的操作行為;
封裝方法的目的
  • 為了:隔離複雜度;

例如我有一個取款的例子:

class ATM:    def __card(self):        print('插卡')    def __auth(self):        print('使用者認證')    def __input(self):        print('輸入取款金額')    def __print——bill(self):        print('列印賬單')    def __take_money(self):        print('取款')    def withdraw(self):        self.__card()        self.__auth()        self.__input()        self.__print_bill()        self.__take_money()    a=ATM()    a.withdraw()
>* 如上述的代碼可以看出,我們外部的執行個體通過,withdraw可以訪問完全;
封裝與擴充性:

以前我們說過:物件導向的優點有:可擴充性高,其實封裝也是可擴充性的高的一個方面;

class Room:    def __init__(self,namek,owner,height,weight,length)        self.name = name        self.owner=owner        #如果只想讓使用者訪問:房間的長度和寬度,這裡我們就可以把寬度和長度變為隱藏;        self.__weight=weight        self.__length=lengthr=Room('房間','wo',10,10)

1.如果問題來了,我們要只想訪問房間的面積而不是房間的屬性呢?

class Room:    def __init__(self,namek,owner,height,weight,length)        self.name = name        self.owner=owner        #如果只想讓使用者訪問:房間的長度和寬度,這裡我們就可以把寬度和長度變為隱藏;        self.__weight=weight        self.__length=length            def tell_area(self):        return self._weight*self.__length        r=Room('房間','wo',10,10)print(r.tell_area())

如上述我們使用者,只需要關心的是:r.tell_area()究竟裡面的邏輯如何我們不用管,這就為我們提供了方便,類的擴充性;

  • 如果計算房間的體積呢?
class Room:    def __init__(self,namek,owner,height,weight,length,height)        self.name = name        self.owner=owner        #如果只想讓使用者訪問:房間的長度和寬度,這裡我們就可以把寬度和長度變為隱藏;        self.__weight=weight        self.__length=length        self.__height=height                    def tell_area(self):        return self._weight*self.__length*self.__height        r=Room('房間','wo',10,10)print(r.tell_area())

同樣對於使用者來說,他們不需關心內部的處理邏輯,他們只需要調用就好了;

property的使用:

例如:如下描述:

實現BMI指數程式:

class People:    def __init__(self,name,weiht,height):        self.name=name        self.weight=weigth        self.height=heightP=People('ll',1.81,75)bmi=p.weight/(p.height ** 2)#或者可以寫成如下的:p.bmi =p.weight / (p.height **2)print(p.bmi)

問題:
如上述的方法bmi,雖然我們實現了,但是我們每次都要定義bmi,是不是很麻煩,而且bmi不是固定的,是隨著人的身高體重變化的,而不是一成不變的,那麼問題來了,我們怎麼實現簡單化呢?

  • 這裡我們可以把bmi,定義成為方法,然後放置在類裡面 ,這樣以後的執行個體只需要調用這個方法就好了,不用每次執行個體化去計算了;
class People:    def __init__(self,name,weiht,height):        self.name=name        self.weight=weigth        self.height=height    def bmi(self):        return self.weight/(p.height ** 2)                P=People('ll',1.81,75)print(p.bmi())#bmi後邊的()意味著調用函數

如上述的代碼,對於使用者而言,他把bmi看成指數,加()他們反而不懂,或者說是會誤解,對於使用者他們就把指數bmi當成了一個名詞,而不是()的方法;使用者最終想實現的其實就是p.bmi
所以要實現p.bmi我要在class類裡面,bmi()上邊加個,裝飾器:

class People:    def __init__(self,name,weiht,height):        self.name=name        self.weight=weigth        self.height=height    @property    def bmi(self):        return self.weight/(p.height ** 2)P=People('ll',1.81,75)print(p.bmi())#bmi後邊的()意味著調用函數

補充一個知識點:property的使用:
比如自己定義一個property的用法;

class People:    def __init__(sefl,name):        self.__name=namep =People('egon') 

如上述我們肯定擷取不到名字怎麼辦呢?

答案:我們肯定要通過介面來擷取名字

class People:    def __init__(sefl,name):        self.__name=name    def get_name(self):        return self.__name        p =People('egon') print(p.get_name())

然後對於使用者而言:他們就想訪問屬性而已,不用通過方法,要不然使用者會懵逼;

那麼問題來了,我們怎麼來搞呢?(答案只有加裝飾器了,如代碼)

class People:    def __init__(sefl,name):        self.__name=name    @property    def get_name(self):        return self.__name        p =People('egon') print(p.name)

這裡我們通過property來說明,另一個property的用法:

class People:    def __init__(sefl,name):        self.__name=name            @property    def name(sefl):        return self.__name    @name.setter    def name(self,val):        if not isinstance(val,str):            print('名字必須是字串類型的')            return        self.__name =val    @name.deleter    def name(self):        print('不讓刪除')            p =People('egon') p.name #這裡觸發的是第一個,return self.__namep.name='DDD'#這個是訪問行為,觸發的是def name(self,val),如上述的修改的邏輯del p.name#刪除屬性

如上述所述:我們之要掌握,不需要掌握太多;

@property    def name(sefl):        return self.__name
  • 總結,如果說一些東西不能像屬性一樣,需要定一個方法來實現,但是使用者又想把這些當做屬性來訪問,而不是方法,()之類的東西,所以要這裡我們需要使用property裝飾之類東西來滿足需要;
    這裡上述的
@property    def name(sefl):        return self.__name
  • 就是一些東西無法通過屬性直接存取的,所以就定義一個方法,然後呢,我們使用者又不懂什麼方法不方法的,使用者要按照屬性一個的訪問,所以這時候就用到了裝飾器;

物件導向之繼承

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.