天天看點

Python學習(24)--面向對象程式設計1

Python學習(24)--面向對象程式設計1

這一節我們将介紹使用面向對象的程式設計思想來組織和編寫Python代碼,首先我們會講解面向對象的思想,類和對象的概念。接着,将會介紹類中一些常用的方法,如構造函數,列印函數,析構函數等等。

1.面向對象思想

面向對象和面向過程都是一種程式設計思想,之前我們編寫的代碼,實作的功能都很簡單,代碼量也不多,也沒有涉及到面向對象的程式設計思想,但當我們需要編寫大量的代碼去完成一個工程時,就需要考慮如何組織代碼來高效的完成這個工程,這個時候就用到了面向對象。那麼什麼是面向對象?

面向對象可以和面向過程對比着來了解.例如蓋一間房子,面向過程考慮的事情是蓋房子的過程,比如先打地基,然後用磚砌牆,再搭房梁等等。面向過程會把蓋房細節和蓋房需要完成任務的先後次序都會林列出來,然後按部就班的完成蓋房子這件事情。

而面向對象考慮的是房子這個對象是由哪些部件組成的,比如一個房子有地基,窗戶,牆,房梁,房頂等等。而不會考慮如何打好地基,如何去砌牆等等這些細節問題,隻會考慮一個房子有什麼?具體房子某一個部分如何做的任務會交給相應的勞工去完成。

2.類的概念

在面向對象中,類是一個抽象的概念,抽象的東西描述的都是事物的共性。例如人就是一個抽象的概念,人的共性有姓名,年齡,身高,體重等等标簽,人的共性還有走路,吃東西等等行為。具體的每個人又有不同的姓名年齡,喜歡吃不同的東西,又展現出具體事物間的個性。

人這種抽象概念,在面向對象的世界裡對應的是一個類;人的共性中的标簽,在面向對象中對應的是類的屬性;人的共性中的行為,在面向對象中對應的是類中的方法。具體的人又是人這個類的執行個體對象。在Python中定義一個類的格式如下:

Python學習(24)--面向對象程式設計1

在Python中定義一個類使用的是關鍵字class,表示這是一個類。後跟類的名字和父類清單,父類清單中是類的父類,涉及到繼承的概念,以後會介紹到。所有的類都會有一個共同的父類(或者稱之為超類或基類),就是object類,如果一個類沒有特殊指定的父類,那麼在定義類時父類清單一般隻有object類,或者為空。最後,在類中定義類的屬性和方法行為。

以人這個抽象概念為例,類的定義代碼如下:

<b>[python]</b> view plain copy

class Person():

    name=""

    age=0

    height=0

    weight=0

    def run(self):

        print("running...")

    def eat(self,food):

print(self.name+" eat "+food)

如上為一個類名為Person的類,父類清單為空,預設直接繼承于object類。Person類的屬性有name,age,height,weight;定義的方法行為有,run(self)和eat(self,food)。這裡需要注意的是,在Python中,每一個類中的方法參數清單不能為空,至少要有參數self,self表示的是類的目前對象。例如,Person類有一個執行個體對象zhangsan,那麼self表示的就是zhangsan這個對象。代碼如下:

zhangsan=Person()#建立一個變量名為zhangsan的Person對象

zhangsan.name="zhangsan"#将對象zhangsan的屬性name的值設定為"zhangsan"

zhangsan.eat("Apple")

通過如上代碼,可以發現建立類的執行個體化對象的方式為:對象名=類名(參數清單),參數清單在之後的構造函數中會介紹到,如zhangsan=Person()就是建立了一個Person類的對象;擷取對象屬性的方式為:對象名.屬性名,如zhangsan.name="zhangsan";對象調用方法的方式為:對象名.方法名(參數清單),如zhangsan.eat("Apple"),為調用Person類中定義的方法eat(self,food),列印結果如下:

Python學習(24)--面向對象程式設計1

Person類的方法eat(self,food)中的代碼如下:

def eat(self,food):

    print(self.name+" eat "+food)

在對象zhangsan調用方法eat(self,food)時,參數self表示的是對象zhangsan;self.name表示的是對象zhangsan的name屬性值:"zhangsan",是以zhangsan.eat("Apple")的列印結果為"zhangsan eat Apple"。

其實,類和Python中其他基本資料類型一樣,都隻是一種資料類型,隻不過類的資料結構更加複雜,更加抽象。使用類建立的對象相當于基本資料類型的一個變量,是占據記憶體空間的一個執行個體。

3.參數self

在類中的,一個方法的參數清單的第一個參數代表的含義是該類的目前對象。之前我們在設計Person類時,方法eat(self,food),其中第一個參數為self,表示的就是Person類的目前對象,但是需要注意的是self并不是一個關鍵字,Python中隻是預設類中方法參數清單的第一個參數代表該類的目前對象,self隻是一個形參名,也可以使用其它形參名來代替,隻不過使用self含義更加見名知意。如下,我們可以換一個形參名來證明以上所述:

    def run(I):

        print(I.name)

    def eat(I,food):

        print(I.name+" eat "+food)

per=Person()

per.name="zhangsan"

per.run()

如上代碼所示,将Person類中方法的參數名self全部替換為I。然後建立一個Person類的對象per,并修改其name屬性的值為"zhangsan",當per調用方法run()時,參數清單第一個參數I表示的就是目前對象per,列印結果如下:

Python學習(24)--面向對象程式設計1

通過列印結果可以看出,将Person類中的方法參數名self全部替換為I後,并沒有出現錯誤提示,這是因為Python預設将類中方法參數清單的第一個參數識别為目前對象,這也決定了類中每一個方法的參數清單至少有一個參數,如果隻有一個參數,那麼這個參數的含義就是代表目前對象。

一般并不建議修改參數名self,這樣降低程式的可讀性。

4.類的構造函數

構造函數用于在建立一個類的執行個體對象時,初始化對象的屬性值。對應到現實中,每個具體的人在出生時,姓名、體重、身高這些屬性都可能有不同的屬性值。而定義一個類的構造函數和定義方法的形式是一樣的,如下是Person類的構造函數:

def __init__(self,name,age,height,weight):

    self.name=name

    self.age=age

    self.height=height

    self.weight=weight

每個類的構造函數的函數名都是__init__,參數清單一般為類的屬性,在構造函數中執行的操作為初始化對象的屬性值。如self.name=name為初始化目前被構造對象的name屬性值。如下代碼:

    def __init__(self,name,age,height,weight):

        self.name=name

        self.age=age

        self.height=height

        self.weight=weight

        print(self.name)

        print(self.name+" eat "+food)

per=Person("zhangsan",12,123,50)

print(per.name,per.age,per.height,per.weight)

如上代碼,通過構造函數建立并初始化了一個Person對象per,并列印per的屬性值,列印結果如下:

Python學習(24)--面向對象程式設計1

需要注意的是,一個類沒有構造函數也能建立這個類的對象,之是以如此,是因為類中有一個預設的構造函數,如下:

def __init__(self):

    pass

如果沒有為類定義構造函數,建立對象時使用的是預設構造函數。

5.析構函數

構造函數是在記憶體中建立 一個類的對象,而析構函數是銷毀該類在記憶體中的對象。在類中定義一個析構函數,用于動态的釋放程式記憶體。但是由于Python中有垃圾回收機制,是以一般不需要使用者自己釋放記憶體。析構函數也一般不常用,這裡隻做簡單的介紹。

在類中定義一個析構函數,就是定義一個函數名為__del__的方法,如下就是一個簡單的析構函數,當使用者銷毀類的執行個體對象時,會調用這個方法。

def __del__(self):

    print("this is person's del")

那麼如何銷毀一個執行個體對象呢?其實和之前介紹的在記憶體中銷毀一個基本類型資料的方式是一樣的,即del 對象名。如下代碼:

    def __del__(self):

        print("this is person's del")

person1=Person("zhangsan",10,123,40)

del person1

如上,建立了一個Person類的對象person1,并銷毀它。當銷毀對象person1時,就會調用Person類的析構函數__del__(self)。代碼列印結果如下:

Python學習(24)--面向對象程式設計1

6.列印函數__str__(self)和__repr__(self)

在Python程式設計過程中,有時候我們可能需要列印一個對象的具體屬性資訊。這個時候就用到了列印函數__str__(self)和__repr__(self)。兩者主要有兩個不同點:一是在指令視窗模式下列印結果的不同;二是優先級的不同。如下我們在不使用列印函數的情況下列印一個對象。

        print(self.__class__)

        person = self.__class__("wangwu", 13, 123, 40)

person1 = Person("zhangsan", 10, 123, 40)

print(person1)

列印的結果如下:

Python學習(24)--面向對象程式設計1

可見在不使用列印函數的情況下,列印一個對象,顯示的隻是對象的類型和對象在記憶體中的位址,而使用者真正關心的對象屬性資訊并沒有列印出來。使用列印函數不僅可以列印使用者真正關心的資訊,還可以可以自定義資訊列印的形式。如下是一個使用列印函數列印對象的例子:

    def __repr__(self):

        return "__repr__:"+self.name+"-"+str(self.age)+"-"+str(self.weight)+"-"+str(self.height)

    def __str__(self):

        return "__str__:"+self.name+"-"+str(self.age)+"-"+str(self.weight)+"-"+str(self.height)

如上,在Person類中定義了兩個列印函數__repr__(self)和__str__(self),都用于列印對象的屬性資訊。列印結果如下:

Python學習(24)--面向對象程式設計1

通過列印結果可見,在列印Person對象時,調用了方法__str__(self),列印了此方法傳回的字元串。如果類中__str__(self)和__repr__(self)兩個列印函數都存在,使用print函數列印對象時,Python會先調用方法__str__(self),因為前者的優先級要比後者的優先級要高。隻有當類中隻有函數__repr__(self)時,列印對象才會調用__repr__(self)。

兩者的不同點還展現在指令視窗的互動模式下,在指令視窗模式下,一般适用于使用__repr__(self)。兩者在列印結果上有着稍微的不同。如下:

Python學習(24)--面向對象程式設計1

如上,當類中隻有方法__repr__(self)時,無論是&gt;&gt;&gt;person 回車或者直接print(person)都會調用Person對象的__repr__(self)方法列印結果。

Python學習(24)--面向對象程式設計1

如上,當類中隻有方法__str__(self)時,print(person)會調用Person對象的方法__str__(self);而&gt;&gt;&gt;person 回車卻沒有調用列印函數,隻是列印的對象的類型和記憶體位址。

Python學習(24)--面向對象程式設計1

如上,在互動模式下,&gt;&gt;&gt;person 回車調用的是列印函數__repr__(self);而print(person)調用的是列印函數__str__(self)。可以這樣了解,在互動模式下&gt;&gt;&gt;對象名 回車,列印一個對象時,列印函數__repr__(self)的優先級要比__str__(self)高,是以使用這種方式列印對象,會調用對象的__repr__(self);而使用print(對象名)列印一個對象時,__str__(self)優先級較高,是以會優先調用函數__str__(self)列印對象。

以上就是這節介紹的所有内容,下一節将會繼續介紹面向對象中的繼承和多态的程式設計思想,敬請期待。