Python基礎(面向對象之封裝與繼承)

代碼的編寫一般分爲三個階段:

1、面向過程編程

針對具體需求的邏輯從上到下實現功能,當邏輯中出現重複的功能,採用的就是複製粘貼代碼的方式來實現。

2、函數式編程

將需求中重複的功能封裝到一個函數中,當邏輯中需要用到時則調用該函數,而無需重複編寫。

3、面向對象編程

Python中一切都是對象,而對象是基於類創建的,根據類創建對象的過程叫實例化,被創建的對象又叫實例,具體到怎麼實現Python的面向對象編程。簡單的解釋就是:

先定義一個類,然後在類中定義不同的方法(函數),不同的方法之間可以共用一組變量,然後根據這個類創建對象,被創建的對象就可以使用類中的方法。

Python面向對象具有以下特性:

1、封裝

  簡單解釋:隱藏對象所使用方法的具體細節。

  普通解釋:在由類創建對象時,每個被創建的對象中都有一個類對象指針,指向創建它的類,對象所使用的方法全部保存在類當中,類中的方法在執行的時候,需要使用的變量保存在對象中,這樣對象所使用的方法對對象來說就是隱藏的,對象只能使用而不能修改這些方法。

  詳細解釋:

class Person:              #class是語法關鍵字 Person是類的名稱
    def __init__(self,name):     #構造方法,根據類創建對象時自動執行
        self.name = name    #構造普通字段(變量),具體意思後面會解釋
        print 'Name is:%s'%self.name

    def say(self):          #定義一個方法,參數self爲必填,且不能改變
        print 'Name Say:%s'%self.name

p1 = Person('zhangsan') #根據Person類創建一個p1對象,在創建的時候會自動執行Person類中的__init__方法將傳入的參數zhangsan封裝到p1的name屬性中,也就是p1.name='zhangsan'。同時會自動生成一個隱藏的類對象指針指向Person類,用來標示p1是由Person類創建的。

p1.say()          #執行p1的say方法,這時p1本身是沒有say方法的,它會根據類對象指針來找到用來創建它的Person類,然後執行Person類中的say方法,say方法需要用到self.name變量,這個變量是保存在對象本身中的,也就是self.name=p1.name,而p1.name在創建p1時已經構造完成,p1.name='zhangsan'
         
p2 = Person('lisi')    #根據Person類創建一個p2對象,在創建的時候會自動執行Person類中的__init__方法將傳入的參數zhangsan封裝到p2的name屬性中,也就是p2.name='lisi'。同時會自動生成一個隱藏的類對象指針指向Person類,用來標示p2是由Person類創建的。

p2.say()          #執行p2的say方法,這時p2本身是沒有say方法的,它會根據類對象指針來找到用來創建它的Person類,然後執行Person類中的say方法,say方法需要用到self.name變量,這個變量是保存在對象本身中的,也就是self.name=p2.name,而p2.name在創建p2時已經構造完成,p2.name='lisi'

執行結果:

Name is:zhangsan 
Name Say:zhangsan
Name is:lisi 
Name Say:lisi

以上例子的語法很簡單,比較繞的可能就是一個self。封裝的重點和難點也就在這個self,下面來具體解釋這個self的意義:

面向對象中同一個類可以創建多個對象,這些對象所具有的方法都是來自於創建他們的類(對照上述例子中的say方法)。

那麼問題來了:多個對象調用的都是同一個類中的同一個方法,那麼方法在執行的時候是怎麼區分是誰在調用它呢?怎麼知道self.name的值該是什麼呢?

這就是self的用處所在:在使用類創建對象的時候,會自動把對象的名稱賦值給類中的self參數。

比如:

p1 = Person('zhangsan')     #使用Person類創建一個名稱叫p1的對象。這時Person類中的__init__方法將會被執行,執行過程就是:
def __init__('p1','zhangsan'):
    p1.name = 'zhangsan'
    print 'Name is:%s'%p1.name
#當執行p1.say()方法時,執行過程是:
def say('p1'):
    print 'Name Say:%s'%p1.name
#其實相當於執行 Person.say('p1')

總結:對象在調用類方法的時候,對象是誰,那麼方法中self的值就是誰。(self本質就是一個形式參數)


2、繼承

  簡單解釋:派生類(子類)繼承基類(父類)的方法。(子承父業)

  普通解釋:Python中支持多繼承(一個類可以繼承多個類),當類是經典類的時候,如果繼承的方法重複則廣度優先(先橫着找),當類是新式類的時候,如果繼承的方法重複則深度優先(先豎着找)。

經典類和新式類的區別就是在定義的時候,新式類會繼承object,如果一個類繼承的父類是新式類,那麼他也是新式類。這裏我們不過多的去解釋新式類和經典類在繼承上的區別,因爲容易把自己繞暈,記住新式類的繼承規則就可以了。

  詳細解釋:

class D(object):        #定義一個新式類D
    def f1(self):       #在類中定義一個f1方法
        print 'D:f1'
class C(D):             #定義一個類C,繼承類D
    def f1(self):       #在類中也定義一個f1方法
        print 'C:f1'
class B(D):             #定義一個類B,繼承類D
    pass                #不定義任何方法
class A(B,C):           #定義一個類A,同時繼承類B和C
    pass                #不定義任何方法

obj = A()               #根據類A創建對象
obj.f1()                #執行f1方法

執行結果:
C:f1

上面程序的執行過程如下:

由於類D繼承了object,所以它是一個新式類。C繼承了D,所以C也是新式類,B也一樣。A繼承了B和C,所以A也是新式類。

對象obj執行f1方法,根據新式類繼承的查找原則,順序如下:

第一步:去A中查找f1方法,未找到。

第二步:去B中查找f1方法,未找到。

    這裏雖然B繼承了D的f1方法,但是由於新式類是先橫着查找,所以不會執行D中的f1方法

第三步:去C中查找f1方法,找到,然後執行,所以結果是C:f1。


繼承中的其他需求用法:

如果在繼承的時候同時希望使用基類(父類)中的字段(變量),該如何實現:

class Person:
        def __init__(self,name):
                print 'Person build self.name'
                self.name = name
        def say(self):
                print 'Person.say'

class Son(Person):                            #定義一個類繼承Person類
        def __init__(self,name,age):
                Person.__init__(self,name)    #執行父類中的構造方法
                print 'Son build self.age'
                self.age = age
                print 'Person name is %s age is %s'%(self.name,self.age)

p1 = Son('lily',17)
p1.say()

執行結果:

Person build self.name

Son build self.age

Person name is lily age is 17

Person.say


下一篇再介紹類的成員和類成員修飾符。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章