Python基礎(chǔ)系列內(nèi)容為學(xué)習(xí)廖雪峰老師Python3教程的記錄,廖雪峰老師官網(wǎng)地址:廖雪峰Python3教程
Author:yooongchun
Email:yooongchun@foxmail.com
面向?qū)ο缶幊毯喗椋好嫦驅(qū)ο缶幊?code>Object Oriented Programming簡稱OOP,是一種區(qū)別于面向過程編程的新的編程思想。OOP把對象作為程序的基本單元,一個(gè)對象包含了數(shù)據(jù)和操作數(shù)據(jù)的函數(shù)。
Python中的所有數(shù)據(jù)類型都可以視為對象,也可以自定義對象。自定義的對象數(shù)據(jù)類型就是面向?qū)ο笾械念?code>class概念。
示例:使用面向?qū)ο蟪绦蛟O(shè)計(jì)思想設(shè)計(jì)一個(gè)存儲學(xué)生信息(姓名和成績)的表為了顯示區(qū)別,我們首先使用面向過程的程序來構(gòu)造:
stu1={'name':'Alex','score':98}stu2={'name':'Bob','score':89}...
然后使用函數(shù)來處理學(xué)生信息
def print_score(stu): print('%s:%s' %(stu['name'],stu['score']))
上面的代碼簡單演示了面向過程設(shè)計(jì)的存儲數(shù)據(jù)到使用數(shù)據(jù)過程。接著我們用面向?qū)ο蟮某绦蛟O(shè)計(jì)思想來實(shí)現(xiàn)。
首先,我們來考慮如何存儲數(shù)據(jù):我們把學(xué)生視為一個(gè)對象,那么姓名和成績就是這個(gè)對象的兩個(gè)屬性,使用數(shù)據(jù)就屬于對象的一個(gè)方法,我們把上面的內(nèi)容轉(zhuǎn)為代碼就是:
class Student(object): def __init__(self,name,score): self.name=name self.score=score def print_score(self): print('%s:%s' %(self.name,self.score))
上面的代碼中我們構(gòu)造了一個(gè)Student
類(對象),還構(gòu)造了一個(gè)對象的方法(Method)print_score
,現(xiàn)在我們就可以來實(shí)例化(Instance)對象
bart=Student('Bart',67)lisa=Student('Lisa',88)
調(diào)用對象的方法
bart.print_score()lisa.print_score()
我們來運(yùn)行測試:
>>> from stu import Student>>> bart=Student('Bart',67)>>> lisa=Student('Lisa',88)>>> bart.print_score()Bart:67>>> lisa.print_score()Lisa:88>>>
這樣,我們就完成了面向?qū)ο蟪绦蛟O(shè)計(jì)的第一個(gè)程序。由上可見,這種程序設(shè)計(jì)思想抽象程度要高于函數(shù),因?yàn)樗劝藬?shù)據(jù),又包括了操作數(shù)據(jù)的方法。
類和實(shí)例:面向?qū)ο笞钪匾母拍罹褪穷悾–lass)和實(shí)例(Instance)。類是抽象的模板,而實(shí)例則是根據(jù)類創(chuàng)建出來的一個(gè)個(gè)具體的對象。
類定義的一般格式,以前面創(chuàng)建的Student類為例
class Student(object): pass
上面Student
代表類名,object
代表繼承的類,這里可以是繼承不同的類,如果沒有繼承類,則使用所有類的公有繼承類object
,pass
里寫類的內(nèi)容,這就是創(chuàng)建類的一般格式。
實(shí)例化類的一般格式,以student類為例
bart=Student('Bart',67)
給類傳入數(shù)據(jù)以后,類就被實(shí)例化為一個(gè)個(gè)對象,比如上面的bart就屬于一個(gè)對象,該對象包括了name
和score
兩個(gè)屬性,還有一個(gè)print_score()
方法。
可以給一個(gè)實(shí)例自由的綁定屬性,比如,為bart實(shí)例添加一個(gè)gender屬性
>>> bart.gender='male'>>> bart.gender'male'
而有一些屬性我們認(rèn)為是必備的,這就可以通過一個(gè)特殊的__init__
方法強(qiáng)制填入,比如前面的
def __init__(self,name,score): self.name=name self.score=score
注意這里的__init__
是前后各兩個(gè)下劃線。
另外,__init__
方法的第一個(gè)參數(shù)永遠(yuǎn)是self
,表示創(chuàng)建的實(shí)例本身。在實(shí)例化對象時(shí),注意要傳入與__init__
方法相對應(yīng)的參數(shù),但是self
不用傳入。
數(shù)據(jù)封裝
面向?qū)ο缶幊痰囊粋€(gè)重要特點(diǎn)就是數(shù)據(jù)封裝。我們還是通過前面定義的Student類來看。對于面向過程的程序設(shè)計(jì),當(dāng)我們完成了數(shù)據(jù)的存儲后,要實(shí)現(xiàn)對數(shù)據(jù)的操作,我們通常會定義一個(gè)方法,比如
def print_score(stu): print('%s:%s' %(stu.name,stu.score))
這樣,方法和數(shù)據(jù)就是獨(dú)立的,但是使用類的概念后,我們直接把這個(gè)方法封裝進(jìn)入類里,這樣,調(diào)用這個(gè)類的方法只需這樣:
stu.print_score()
可見,我們只關(guān)心操作對象的方法,而不關(guān)心其內(nèi)部是如何實(shí)現(xiàn)的,這就是封裝的優(yōu)勢所在。
注意,在類內(nèi)部寫方法時(shí),也需要把第一個(gè)參數(shù)置為self
,至于其他的參數(shù)等都和普通函數(shù)完全一樣,在調(diào)用時(shí)也同樣不用傳入self參數(shù)。
訪問限制:Python通過在變量前添加兩個(gè)下劃線來把變量申明為私有private
,比如,前面的Student,你現(xiàn)在在外部仍可以修改內(nèi)部代碼
>>> bart=Student('Bart',99)>>> bart.score=78>>> bart.score78>>>
現(xiàn)在我們給類的name
和score
屬性添加__
,讓外部不可訪問
class Student(object):def __init__(self,name,score): self.__name=name self.__score=scoredef print_score(self): print('%s:%s' %(self.__name,self.__score))
現(xiàn)在我們再來嘗試從外部訪問
>>> bart=Student('Bart',99)>>> bart.__nameTraceback (most recent call last):File "<stdin>", line 1, in <module>AttributeError: 'Student' object has no attribute '__name'
發(fā)現(xiàn),程序報(bào)錯(cuò)了,可見,通過添加__
,程序把變量相應(yīng)申明為私有了,這時(shí),我們通過在程序內(nèi)部提供公有的函數(shù)(public
)來讓外部使用
def getName(self): return self.__namedef setName(self,name): self.__name=name
這樣,我們就把內(nèi)部的變量完全封裝了。
>>> bart=Student('Bart',99)>>> bart.setName('BART')>>> bart.getName()'BART'