面向過程編程和對象編程都是程序設(shè)計思想押框,面向過程程序設(shè)計是將需要實(shí)現(xiàn)的功能流程化列出來岔绸,讓程序依次按照命令執(zhí)行。跟面向過程程序設(shè)計不同橡伞,面向?qū)ο缶幊淌菍F(xiàn)實(shí)中的個體的狀態(tài)和行為抽象化成對象的屬性和方法盒揉,通過對象間的方法進(jìn)行信息處理和通信模擬現(xiàn)實(shí)世界中的實(shí)體交互,高度抽象的設(shè)計思想可以模擬現(xiàn)實(shí)中的情景和需求兑徘,更方便地面對大型程序設(shè)計的需要刚盈。
Python是一門面向?qū)ο缶幊痰恼Z言,其將所有的數(shù)據(jù)類型都視為對象挂脑。其中最重要的概念是類和實(shí)例藕漱。類是為某一個現(xiàn)實(shí)對象創(chuàng)建出的模板欲侮,其包含了該對象所擁有的屬性和方法,通過實(shí)例化對類進(jìn)行個性化設(shè)定便創(chuàng)造出實(shí)例肋联。
1.Class 和 Instance
類是作為對象的模板威蕉,可以在里面設(shè)定公共屬性(類屬性)、實(shí)例屬性(對象屬性)橄仍、構(gòu)造器和方法
class Dog(object):
#類屬性默認(rèn)用大寫命名
CATEGORY = '犬屬'
#構(gòu)造器由__init__命名韧涨,括號內(nèi)包括固定參數(shù)self和實(shí)例屬性
def __init__(self,name,ages):
self.name = name
self.__ages = ages
#方法的括號第一個參數(shù)一定是self,可加其他參數(shù)
def run(self,state):
print("狗兒跑得"+state+"侮繁,我叫"+self.name)
#將屬性復(fù)制功能封裝在函數(shù)中提供了一定的安全性虑粥,并且可以在賦值中添加校準(zhǔn)及其他功能。
def setAges(self,ages):
if type(ages) == int:
self.__ages = ages
else:
print("你輸入的不是數(shù)字宪哩,不能充當(dāng)年齡")
def getAges(self):
return self.__ages
dog = Dog("旺財",12)
print(dog.CATEGORY)
dog.run("慢")
dog.setAges(10)
print(dog.getAges())
結(jié)果為:
>犬屬
>狗兒跑得慢娩贷,我叫旺財
>10
在上面的實(shí)例屬性設(shè)定中出現(xiàn)了__ages
這樣子以雙下劃線開頭的屬性定義,這標(biāo)志著是private變量锁孟,不準(zhǔn)許通過實(shí)例.變量
的方式來讀取彬祖,這種保護(hù)機(jī)制便確保了外部程序沒辦法隨意修改對象內(nèi)部的狀態(tài)。其實(shí)本質(zhì)上解釋器會將該變量名轉(zhuǎn)化為_Dog__ages
在其前面添加上_類名
dog.__ages = 1
# 僅僅是為實(shí)例創(chuàng)建了一個新的屬性而已罗岖,動態(tài)語言確實(shí)可以運(yùn)行時添加屬性
print(dog.getAges())
print(dog.__ages)
# __ages在實(shí)例化時已經(jīng)變成了_Dog__ages
dog._Dog__ages = 13
print(dog.getAges())
結(jié)果是:
>10
>1
>13
注意
:有些時候在類定義中出現(xiàn)了了一個下劃線開的實(shí)例變量名涧至,這樣的實(shí)例變量在程序?qū)用嫔鲜强梢哉TL問的,但是按照約定俗成的規(guī)定桑包,這種命名形式是告訴使用者將其看成私有變量南蓬,不要從外面進(jìn)行訪問。
2.類屬性和實(shí)例屬性
類屬性是指該變量歸類所有哑了,所有新創(chuàng)建的實(shí)例都可以訪問得到赘方,但只能通過類名索引的方式來修改勒邊來那個。Python可以在類定義中用self定義實(shí)例變量弱左,作為動態(tài)語言也可以在程序執(zhí)行過程中通過實(shí)例直接創(chuàng)建實(shí)例變量窄陡。
>>> class Dog():
name = "旺財"
>>> dog = Dog()
# 訪問類變量
>>> dog.name
'旺財'
# 綁定新的實(shí)例屬性
>>> dog.ages = 12
>>> dog.ages
12
# 實(shí)例屬性覆蓋類屬性
>>> dog.name = "耿狗"
>>> dog.name
'耿狗'
# 刪除實(shí)例屬性,重新可以訪問類屬性
>>> del dog.name
>>> dog.name
'旺財'
# 重新定義類屬性
>>> Dog.name = "lal"
>>> Dog.name
'lal'
# 測試是不是真正刪除類屬性
>>> del Dog.name
>>> Dog.name
Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
Dog.name
AttributeError: type object 'Dog' has no attribute 'name'
python作為動態(tài)語言可以在運(yùn)行過程中為實(shí)例綁定新的實(shí)例屬性(對類和對其他實(shí)例無效)拆火,如上面所示為Dog實(shí)例dog綁定了新的實(shí)例屬性ages跳夭。有時候我們可能希望限制綁定的屬性,python提供了slots特殊類屬性來限定可動態(tài)綁定的實(shí)例屬性们镜,在類定義的時候?qū)⒖赡苄枰獎討B(tài)綁定的實(shí)例屬性名創(chuàng)建成一個元組賦給slots類屬性币叹,綁定除了指定屬性外的實(shí)例屬性將會出現(xiàn)錯誤。
class Dog(object):
__slots__ = ('name','ages')
dog = Dog()
dog.color = yellow
結(jié)果為:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Dog' object has no attribute 'color'
3.枚舉類與元類
在python中可以用大寫字母來設(shè)定常量模狭,表明不可修改颈抚,但是這并不是一種語言機(jī)制而是一種自覺機(jī)制,有被篡改的風(fēng)險嚼鹉。在python3.4中添加了枚舉類便于大小一定的特殊類的定義贩汉,如季節(jié)驱富、工作日等。
枚舉類有兩種不同的設(shè)定形式匹舞,一種便是按照類定義的形式繼承Enum類褐鸥,可以在類中自定義的設(shè)定每一個成員的具體值,或者可以用Enum函數(shù)直接對每一個成員自動編排值策菜。
from enum import Enum,unique
# 用@unique使枚舉類成員的值都是唯一的
@unique
class Season(Enum):
spring = 1
sunner = 2
autumn = 3
winter = 4
# 可以用Eunm函數(shù)直接定義
Season = Enum('Season',('spring','sunner','autumn','winter'))
其中以枚舉類名.成員名的形式來索引每一個成員晶疼,每一個成員都有其名字和值酒贬,可以調(diào)用枚舉類內(nèi)部的members變量來獲取包含全部成員情況的字典
spring = Season.spring
print(spring.name)
print(spring.value)
for name, member in Season.__members__.items():
print(name, '=>', member, ',', member.value)
輸出:
>spring
>1
>Season.sunner
>spring => Season.spring , 1
>sunner => Season.sunner , 2
>autumn => Season.autumn , 3
>winter => Season.winter , 4
>Season.spring
>Season.sunner
>Season.autumn
>Season.winter
4.繼承與多態(tài)
上面舉的例子Dog類繼承了object類又憨,故object稱為Dog類的Super class,Dog類為Subclass锭吨,子類通過繼承獲得了父類的全部成分蠢莺,并且擁有重新復(fù)寫成分的能力。
class WangCai(Dog):
def __init__(self,state,name,ages):
self.state = state
self.name = name
self.ages = ages
def run(self):
print("我是子類的旺財")
super().run(self.state)
wangcai = WangCai("慢","旺財",12)
wangcai.run()
結(jié)果為:
>我是子類的旺財
>狗兒跑得慢零如,我叫旺財
多態(tài)一般是指在靜態(tài)類型語言中的子類可以傳入需要父類做參數(shù)的函數(shù)躏将,在運(yùn)行的時候調(diào)用子類的相關(guān)內(nèi)容,包含了編譯時類型和運(yùn)行時類型的概念考蕾。這樣一來原先為父類編寫的方法也可以操作子類,而不需要從新定義新的函數(shù)肖卧,大大降低了開發(fā)成本塞帐。但是其實(shí)像python這種動態(tài)類型的語言葵姥,設(shè)定的參數(shù)并不需要提前設(shè)定類型榔幸,參數(shù)引用的對象是具體運(yùn)行到的時候才定義的,因此在實(shí)際操作時可以靈活很多牍疏。只要滿足函數(shù)中所需的調(diào)用的成分麸澜,就可以充當(dāng)參數(shù)傳入并在函數(shù)內(nèi)部進(jìn)行調(diào)用炊邦。這就是動態(tài)語言的“鴨子類型”,它并不要求嚴(yán)格的繼承體系窄俏,一個對象只要“看起來像鴨子碘菜,走起路來像鴨子”忍啸,那它就可以被看做是鴨子。