面向?qū)ο缶幊毯喎QOOP,是一種程序設(shè)計(jì)思想斯议。OOP把對象作為程序的基本單元,一個對象包含了數(shù)據(jù)和操作數(shù)據(jù)的函數(shù)醇锚。
class Person:
# 類屬性
__privateCount = 1 #私有
publicCount = 2 #公共
def __init__(self,name,age):
#創(chuàng)建屬性并給屬性賦值
self.name = name
self.age = age
def readCount(self):
print('%d 私有變量'%self.__privateCount)
print('%d 公有變量'%self.publicCount)
class Teacher(Person):
def teach(self):
print('老師教學(xué)生')
class Student(Person):
# 重載構(gòu)造方法
def __ init __(self,name,idno):
self.name = name
self.idno = idno
# 重載eat方法
def eat(self):
self.__run()
print('%s吃飯'%self.name)
# 私有方法哼御,外部無法調(diào)用
def __run(self):
print('吃完飯跑步')
1.類
類是抽象的模板,通過類實(shí)例化無數(shù)的對象焊唬。就相當(dāng)于類是工廠里生產(chǎn)的模具恋昼,而對象則是模具下生產(chǎn)的商品。
類的聲明:
通過class聲明一個類赶促,縮進(jìn)表示一個類的作用域液肌,類名通常是大寫開頭的單詞。如果有繼承的類鸥滨,通過小括號中引用要繼承的類嗦哆。表示該類的繼承谤祖,如果沒有填寫繼承類,默認(rèn)繼承object類老速,這是所有類最終都會繼承的類粥喜。
2.對象
#繼承父類構(gòu)造方法,必須傳遞父類構(gòu)造方法中需要傳遞的參數(shù)
teacher = Teacher('王老師','42')
#輸出:老師教學(xué)生---自己的方法
teacher.teach()
#輸出:吃飯 --- 繼承父類方法
teacher.eat()
#輸出:王老師 ---屬性的訪問
teacher.name
# age 屬性銷毀
del teacher.age
student = Student('張三','190614')
#輸出:學(xué)生吃飯---重載
student.eat()
#輸出:190614 ---屬性的訪問
student.idno
- 對象(實(shí)例)屬性:
可以通過self或者對象進(jìn)行創(chuàng)建和訪問橘券。在構(gòu)造函數(shù)中self.name和self.age創(chuàng)建name屬性和age屬性额湘。
創(chuàng)建原則:如果屬性不存在,就會創(chuàng)建屬性约郁,存在的話缩挑,就修改屬性值。
屬性的創(chuàng)建和訪問也可以使用內(nèi)置函數(shù)進(jìn)行:
setattr(對象名,屬性名,屬性值)
getattr(對象名,屬性名)
- 類屬性(變量):
直接在類中且在函數(shù)體外定義的變量,是類屬性或者類變量鬓梅。定義之后雖然這個變量屬于類所有供置,但類的所有對象都可以訪問到。
注意:千萬不要對實(shí)例屬性和類屬性使用相同的名字绽快,因?yàn)橄嗤Q的實(shí)例屬性將屏蔽掉類屬性
- self 含義:
在類內(nèi)部方法中引用的self,表示的是對象而不是類芥丧。如方法聲明中的第一參數(shù)self表示的是對對象的引用,其指向的也是對象的地址坊罢。
也可以這樣理解self:方法的調(diào)用续担,是通過對象來進(jìn)行,可以把self,理解為把當(dāng)前對象當(dāng)成參數(shù)傳遞到方法內(nèi)部活孩,進(jìn)行引用物遇。通過self,在方法內(nèi)部,訪問對象的屬性和方法憾儒。
注意:類中的方法聲明询兴,第一個參數(shù)必須顯示的引用self,調(diào)用時忽略該參數(shù)的傳遞。
- 私有方法和屬性的聲明:
通過雙下劃線__來聲明,只允許這個類本身進(jìn)行訪問起趾。例如Person類中的__privateCount屬性就是私有屬性诗舰,在該類中可以使用,引用時必須帶有雙下劃線训裆。在外部或者說別的類中眶根,通過對象去引用這個私有變量(屬性)會報(bào)錯,找不到改變量(屬性)边琉。
3.繼承
繼承是面向?qū)ο蟮闹匾卣髦皇舭伲ㄟ^繼承可以實(shí)現(xiàn)方法和屬性的重用。承創(chuàng)建的新類稱為子類或派生類变姨,被繼承的類稱為基類诸老、父類或超類。
如:Person類就是父類或者說基類钳恕,Teacher 和 Student 類就是子類或者說派生類别伏。
父類的屬性和方法都會被子類繼承,在子類中可以直接進(jìn)行使用忧额。如:Teacher 類中厘肮,teacher對象可以直接使用eat()方法和name和age屬性。
方法的重載:
在父類中繼承下來的方法睦番,可以同過重寫类茂,來進(jìn)行改造滿足自己的實(shí)際需求。這種方式叫做重載托嚣。
方法在調(diào)用時:如果子類中沒有進(jìn)行方法的重寫就會調(diào)用父類的方法巩检。重寫之后,會直接調(diào)用重寫后的方法示启。
注意:子類如果重寫了構(gòu)造函數(shù)兢哭,那么父類的構(gòu)造函數(shù)失效,在父類構(gòu)造函數(shù)中生成的屬性也是失效的夫嗓。如:Student類迟螺,Student中只有name和idno屬性,而Teacher類繼承了父類的name和age屬性舍咖。
多重繼承:繼承多個父類矩父,在類聲明中,父類之間用逗號隔開(橫向)
多層繼承: C類繼承自B類排霉,B類繼承自A類窍株,以此類推,就是多層繼承
4.多態(tài)
多態(tài)也是面向?qū)ο笾匾奶卣髦还ツMㄟ^一個單獨(dú)的例子球订,來理解多態(tài)。
class Person:
def eat(self):
print('吃飯')
class Teacher(Person):
def eat(self):
print('老師吃飯')
class Student(Person):
def eat(self):
print('學(xué)生吃飯')
class Me:
def runEat(self,person):
person.eat()
# 調(diào)用演示
teacher = Teacher()
student = Student()
me = Me()
# 輸出:老師吃飯
me.runEat(teacher)
#輸出:學(xué)生吃飯
me.runEat(student)
通過上面的例子可以看到,任何依賴Person 作為參數(shù)的函數(shù)或者方法都可以不加修改的正常運(yùn)行辙诞,并調(diào)用各自類中的eat方法,這就是多態(tài)的特性辙售。
無需知道傳入的確切類型,由運(yùn)行時決定飞涂,調(diào)用方只管調(diào)用旦部,不管細(xì)節(jié)。對于Python這樣的動態(tài)語言來說较店,則不一定需要傳入Person類型士八。我們只需要保證傳入的對象有一個eat()方法。
動態(tài)語言的“鴨子類型”:它并不要求嚴(yán)格的繼承體系梁呈,一個對象只要“看起來像鴨子婚度,走起路來像鴨子”,那它就可以被看做是鴨子官卡。
注:其實(shí)我們我們可以把runEat方法的參數(shù)person,當(dāng)成是一個變量蝗茁,Python中的變量并沒有限定其數(shù)據(jù)類型醋虏,都是在運(yùn)行時決定的,我們只要保證person的實(shí)參哮翘,有run()方法即可颈嚼。
與OC 面向?qū)ο蠖鄳B(tài)的區(qū)別:OC的多態(tài)必須有繼承關(guān)系,而且runEat方法的參數(shù)person必須指定數(shù)據(jù)類型Person,這樣才可以形成多態(tài)饭寺。
由于繼承關(guān)系阻课,teacher 對象既屬于Teacher 類也是屬于Person 類的,可以通過isinstance(對象名,類名)來進(jìn)行驗(yàn)證艰匙。
5.引用計(jì)數(shù)
Python的內(nèi)存回收機(jī)制是通過引用計(jì)數(shù)來實(shí)現(xiàn)的限煞。當(dāng)對象的引用計(jì)數(shù)變?yōu)?時,它會被回收员凝,但不是立即的署驻,有解釋器在適當(dāng)?shù)臅r機(jī),將垃圾對象的占用的內(nèi)存空間回收绊序。
對象被創(chuàng)建時硕舆,引用計(jì)數(shù)為1。該對象每被引用一次引用計(jì)數(shù)都會加1骤公。當(dāng)對象的引用減少時抚官,引用計(jì)數(shù)減1。引用計(jì)數(shù)為0時阶捆,對象釋放凌节。
單下劃線、雙下劃線洒试、頭尾雙下劃線說明:
_count: 表示該變量是protected類型倍奢,只能在其本身和子類中訪問調(diào)用。
__count: 表示該變量是private類型垒棋,只能在這個類本身中進(jìn)行訪問卒煞。
__ init __ :一般是系統(tǒng)保留定義的名字。