面向?qū)ο蟮脑O計思想是從自然界中來的,因為在自然界中世蔗,類(Class)和實例(Instance)的概念是很自然的。Class是一種抽象概念,比如我們定義的Class——Student喊熟,是指學生這個概念,而實例(Instance)則是一個個具體的Student姐刁,比如芥牌,Bart Simpson和Lisa Simpson是兩個具體的Student。
所以聂使,面向?qū)ο蟮脑O計思想是抽象出Class壁拉,根據(jù)Class創(chuàng)建Instance。
面向?qū)ο蟮某橄蟪潭扔直群瘮?shù)要高柏靶,因為一個Class既包含數(shù)據(jù)弃理,又包含操作數(shù)據(jù)的方法。
在Python中屎蜓,定義類是通過class關鍵字:
class Student(object): pass
創(chuàng)建實例是通過類名+()實現(xiàn)的:>>> bart = Student()
通過定義一個特殊的__init__
方法痘昌,在創(chuàng)建實例的時候,就把name炬转,score等屬性綁上去:
class Student(object): def __init__(self, name, score): self.name = name self.score = score
注意到__init__
方法的第一個參數(shù)永遠是self辆苔,表示創(chuàng)建的實例本身,因此扼劈,在__init__
方法內(nèi)部驻啤,就可以把各種屬性綁定到self,因為self就指向創(chuàng)建的實例本身荐吵。有了__init__
方法骑冗,在創(chuàng)建實例的時候,就不能傳入空的參數(shù)了捍靠,必須傳入與__init__
方法匹配的參數(shù)沐旨,但self不需要傳,Python解釋器自己會把實例變量傳進去:
>>> bart = Student('Bart Simpson', 59)
>>> bart.name
'Bart Simpson'
>>> bart.score
59
和普通的函數(shù)相比榨婆,在類中定義的函數(shù)只有一點不同磁携,就是第一個參數(shù)永遠是實例變量self,并且良风,調(diào)用時谊迄,不用傳遞該參數(shù)闷供。除此之外,類的方法和普通函數(shù)沒有什么區(qū)別统诺,所以歪脏,你仍然可以用默認參數(shù)、可變參數(shù)粮呢、關鍵字參數(shù)和命名關鍵字參數(shù)婿失。
數(shù)據(jù)封裝
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))
這樣一來,我們從外部看Student類啄寡,就只需要知道豪硅,創(chuàng)建實例需要給出name和score
,而如何打印挺物,都是在Student類的內(nèi)部定義的懒浮,這些數(shù)據(jù)和邏輯被“封裝”起來了,調(diào)用很容易识藤,但卻不用知道內(nèi)部實現(xiàn)的細節(jié)砚著。
>>> bart.print_score()
Bart Simpson: 59
和靜態(tài)語言不同,Python允許對實例變量綁定任何數(shù)據(jù)痴昧,也就是說稽穆,對于兩個實例變量,雖然它們都是同一個類的不同實例赶撰,但擁有的變量名稱都可能不同:
>>> bart = Student('Bart Simpson', 59)
>>> lisa = Student('Lisa Simpson', 87)
>>> bart.age = 8
>>> bart.age
8
>>> lisa.age
Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Student' object has no attribute 'age'
從前面Student類的定義來看秧骑,外部代碼還是可以自由地修改一個實例的name、score屬性. 如果要讓內(nèi)部屬性不被外部訪問扣囊,可以把屬性的名稱前加上兩個下劃線__
,在Python中绒疗,實例的變量名如果以__
開頭侵歇,就變成了一個私有變量(private),只有內(nèi)部可以訪問吓蘑,外部不能訪問惕虑,所以,我們把Student類改一改:
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))
改完后磨镶,對于外部代碼來說溃蔫,沒什么變動,但是已經(jīng)無法從外部訪問實例變量.__name
和實例變量.__score
了:
>>> bart = Student('Bart Simpson', 98)
>>> bart.__name
Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Student' object has no attribute '__name'
但是如果外部代碼要獲取name和score怎么辦琳猫?可以給Student類增加get_name和get_score
這樣的方法
如果又要允許外部代碼修改score怎么辦伟叛?可以再給Student類增加set_score方法
雙下劃線開頭的實例變量是不是一定不能從外部訪問呢?其實也不是脐嫂。不能直接訪問__name
是因為Python解釋器對外把__name
變量改成了_Student__name
统刮,所以紊遵,仍然可以通過_Student__name
來訪問__name
變量:
>>> bart._Student__name
'Bart Simpson'