數(shù)據(jù)封裝
?類型封裝的步驟
1. 抽象一個(gè)類型踊跟,完成類的定義
2. 使用__slots__魔法屬性滥壕,限制當(dāng)前類的屬性列表
3. 所有屬性私有化
4. 給每個(gè)屬性,提供set/get方法
備注:關(guān)于擴(kuò)展屬性(就是創(chuàng)建好對(duì)象之后增加的屬性)昌屉,主要是預(yù)留下來丸凭,給共享的數(shù)據(jù)使用的
如果對(duì)象中福扬,有需要共享的數(shù)據(jù)腕铸,可以選擇使用這樣的屬性。
面向?qū)ο缶幊痰囊粋€(gè)重要特點(diǎn)就是數(shù)據(jù)封裝铛碑。在上面的Student類中狠裹,每個(gè)實(shí)例就擁有各自的name和score這些數(shù)據(jù)。我們可以通過函數(shù)來訪問這些數(shù)據(jù)汽烦,比如打印一個(gè)學(xué)生的成績(jī):
>>>def print_score(std):..
.print('%s: %s'% (std.name, std.score))...
>>>print_score(bart)Bart Simpson:59
但是涛菠,既然Student實(shí)例本身就擁有這些數(shù)據(jù),要訪問這些數(shù)據(jù)撇吞,就沒有必要從外面的函數(shù)去訪問俗冻,可以直接在Student類的內(nèi)部定義訪問數(shù)據(jù)的函數(shù),這樣牍颈,就把“數(shù)據(jù)”給封裝起來了迄薄。這些封裝數(shù)據(jù)的函數(shù)是和Student類本身是關(guān)聯(liá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è)方法煮岁,除了第一個(gè)參數(shù)是self外讥蔽,其他和普通函數(shù)一樣。要調(diào)用一個(gè)方法画机,只需要在實(shí)例變量上直接調(diào)用冶伞,除了self不用傳遞,其他參數(shù)正常傳入:
>>>bart.print_score()
Bart Simpson:59
這樣一來步氏,我們從外部看Student類响禽,就只需要知道,創(chuàng)建實(shí)例需要給出name和score荚醒,而如何打印芋类,都是在Student類的內(nèi)部定義的,這些數(shù)據(jù)和邏輯被“封裝”起來了腌且,調(diào)用很容易梗肝,但卻不用知道內(nèi)部實(shí)現(xiàn)的細(xì)節(jié)。
封裝的另一個(gè)好處是可以給Student類增加新的方法铺董,比如get_grade:
class Student(object)
def get_grade(self):
if self.score >=90:
return'A'?
?elif ?self.score >=60:
return'B'
else:
? ? ? ?return'C'
同樣的巫击,get_grade方法可以直接在實(shí)例變量上調(diào)用,不需要知道內(nèi)部實(shí)現(xiàn)細(xì)節(jié):
>>>bart.get_grade()'C'
類是創(chuàng)建實(shí)例的模板精续,而實(shí)例則是一個(gè)一個(gè)具體的對(duì)象坝锰,各個(gè)實(shí)例擁有的數(shù)據(jù)都互相獨(dú)立,互不影響重付;
方法就是與實(shí)例綁定的函數(shù)顷级,和普通函數(shù)不同,方法可以直接訪問實(shí)例的數(shù)據(jù)确垫;
通過在實(shí)例上調(diào)用方法弓颈,我們就直接操作了對(duì)象內(nèi)部的數(shù)據(jù)帽芽,但無需知道方法內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)。
和靜態(tài)語言不同翔冀,Python允許對(duì)實(shí)例變量綁定任何數(shù)據(jù)导街,也就是說,對(duì)于兩個(gè)實(shí)例變量纤子,雖然它們都是同一個(gè)類的不同實(shí)例搬瑰,但擁有的變量名稱都可能不同:
>>> 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'
方法重載
在同一個(gè)類中,出現(xiàn)了兩個(gè)或者兩個(gè)以上同名函數(shù)/方法:方法重載
self.__nickname=nickname
@property
def username(self):
return self.__username
@username.setter
defusername(self,un):
self.__username=un
def password(self):
return self.__password
def password(self,pa):
self.__password=pa
def nickname(self):
return self.__nickname
def nickname(self,ni):
self.__nickname=ni
對(duì)象的屬性
?給創(chuàng)建的對(duì)象控硼,添加屬性
?如果對(duì)象的屬性泽论,可以任意自定義的話,就會(huì)造成非常大的困擾:對(duì)象變成了變形金剛
項(xiàng)目往往時(shí)多個(gè)人協(xié)同開發(fā)的卡乾,開發(fā)的過程中翼悴,每個(gè)人給對(duì)象添加的屬性名稱和屬性個(gè)數(shù)就可能不一致!
class Users:
def__init__(self,name,age):
self.__name=name
self.__age=age
def get_name(self):
return self.__name
def get_age(self):
return self.__age
#def __str__(self):
#return"姓名:%s,年齡:%s"%(self.__name,self.__age)
u=Users("湯姆",20)
print(u)
u.username="admain"
u.password="123"
u.nickname="nini"
print(u.username,u.password,u.nickname,u.get_name(),u.get_age())
運(yùn)行結(jié)果
<__main__.Users object at 0x01E90670>
admain 123 nini 湯姆 20
對(duì)象屬性的限制
為了避免幔妨,對(duì)象屬性被濫用(創(chuàng)建對(duì)象后抄瓦,給對(duì)象增加屬性)
要給對(duì)象的屬性 添加限制 限制對(duì)象只能擁有哪些屬性 魔法屬性__slots__
class Users:
設(shè)置當(dāng)前類創(chuàng)建的對(duì)象 可能出現(xiàn)的屬性列表 列表中沒有出現(xiàn)的屬性不允許使用
__slots__=["__username","__password","__nickname","__sex","__age"]
def__init__(self,username,password,nickname,sex,age):
self.__username=username
self.__password=password
self.__nickname=nickname
self.__sex=sex
self.__age=age
def__str__(self):
return"用戶名:%s,密碼:%s,昵稱:%s,性別:%s,年齡:%s"%(\
self.__username,self.__password,self.__nickname,self.__sex,self.__age)
u=Users("123","123","marre","女","12")
u.address="駐馬店"
print(u)
運(yùn)行結(jié)果
u.address="駐馬店"
AttributeError: 'Users' object has no attribute 'address'
把u.address="駐馬店"注釋掉得到的結(jié)果
用戶名:123,密碼:123,昵稱:marre,性別:女,年齡:12