Python中的類與對象之描述符_第1頁
Python中的類與對象之描述符_第2頁
Python中的類與對象之描述符_第3頁
Python中的類與對象之描述符_第4頁
Python中的類與對象之描述符_第5頁
已閱讀5頁,還剩1頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

Python中的類與對象之描述符描述符(descriptors)是python語言中一個深奧但卻重要的一部分。它們廣泛應(yīng)用于python語言的內(nèi)核,熟練掌握描述符將會為python程序員的工具箱添加一個額外的技巧。下面是小編為大家整理的Python中的類與對象之描述符,歡迎大家借鑒與參考,希望對大家有所幫助。1、假設(shè)一個程序中,我們需要對一個對象屬性執(zhí)行嚴(yán)格的類型檢查。然而,Python是一種動態(tài)語言,所以并不支持類型檢查,但是這并不妨礙我們實現(xiàn)自己版本,且較為初級的類型檢查。對象屬性類型檢查的傳統(tǒng)方法可能采用下面的方式:definit(self,name,age):ifisinstance(str,name):=nameelse:raiseTypeError("Mustbeastring")ifisinstance(int,age):self.age=ageelse:raiseTypeError("Mustbeanint")上面是執(zhí)行這種類型檢查的一種方法,但是參數(shù)數(shù)量增加時它將變得比較繁瑣。另外,在賦值之前,我們可以創(chuàng)建一個在init中調(diào)用的type_check(type,val)函數(shù),但是當(dāng)我們想在其他地方設(shè)置屬性值時,該如何簡單地實現(xiàn)這種檢查呢。我想到的一個快速解決方案是Java中的getters和setters,但是這并不符合Python風(fēng)格,并且比較麻煩。2、假設(shè)在一個程序中,我們想創(chuàng)建一些在運行時立刻初始化然后變成只讀的屬性。有人也能想到利用Python中的特殊方法來實現(xiàn),但這種實現(xiàn)方法仍舊是笨拙和繁瑣的。3、最后,設(shè)想一個程序中,我們希望以某種方式自定義對象屬性的訪問。例如需要記錄這種屬性的訪問。同樣的,還是可以想到一個解決方法,即使這種解決方案可能比較笨重并且不可復(fù)用。上述問題因都與屬性引用相關(guān)而全部聯(lián)系在了一起。下面,我們將嘗試自定義屬性的訪問方法。Python描述符針對上面所列的問題,描述符提供了優(yōu)雅、簡潔、健壯和可重用的解決方案。簡而言之,一個描述符就是一個對象,該對象代表了一個屬性的值。這就意味著如果一個賬戶對象有一個屬性“name”,那么描述符就是另一個能夠用來代表屬性“name”持有值的對象。描述符協(xié)議中“定義了get”、“set”或””這些特殊方法,描述符是實現(xiàn)其中一個或多個方法的對象。這些方法中每一種方法的簽名如下所示:pythondescr.get(self,obj,type=None)->value。descr.set(self,obj,value)-->Nonedescr.(self,obj)-->No實現(xiàn)get方法的對象是非數(shù)據(jù)描述符,意味著在初始化之后它們只能被讀取。而同時實現(xiàn)get和set的對象是數(shù)據(jù)描述符,意味著這種屬性是可寫的。為了更好地理解描述符,我們給出針對上述問題基于描述符的解決方法。使用Python描述符實現(xiàn)對象屬性的類型檢查將是一個非常簡單的任務(wù)。裝飾器實現(xiàn)這種類型檢查的代碼如下所示:classTypedProperty(object):definit(self,name,type,default=None):="_"+nameself.type=typeself.default=defaultifdefaultelsetype()defget(self,instance,cls):returngetattr(instance,,self.default)def___set__(self,instance,value):ifnotisinstance(value,self.type):raiseTypeError("Mustbea%s"%self.type)setattr(instance,,value)raiseAttributeError("Cantattribute")classFoo(object):name=TypedProperty("name",str)num=TypedProperty("num",int,42)>>="obi">>printacct.num>>print#tryingtoassignastringtonumberfails在這個例子中,我們實現(xiàn)了一個描述符TypedProperty,并且這個描述符類會對它所代表的類的任何屬性執(zhí)行類型檢查。注意到這一點很重要,即描述符只能在類級別進(jìn)行合法定義,而不能在實例級別定義。例如,在上面例子中的init方法里。當(dāng)訪問類Foo實例的任何屬性時,描述符會調(diào)用它的get方法。需要注意的是,get方法的第一個參數(shù)是描述符代表的屬性被引用的源對象。當(dāng)屬性被分配時,描述符會調(diào)用它的set方法。為了理解為什么可以使用描述符代表對象屬性,我們需要理解Python中屬性引用解析的執(zhí)行方式。對于對象來說,屬性解析機制在object.__getattribute()中。該方法將b.x轉(zhuǎn)換成type(b).__dict[x].__get(b,type(b))。然后,解析機制使用優(yōu)先級鏈搜索屬性,在優(yōu)先級鏈中,類字典中發(fā)現(xiàn)的數(shù)據(jù)描述符的優(yōu)先級高于實例變量,實例變量優(yōu)先級高于非數(shù)據(jù)描述符,如果提供了getattr(),優(yōu)先級鏈會為getattr()分配最低優(yōu)先級。對于一個給定的對象類,可以通過自定義getattribute方法來重寫優(yōu)先級鏈。深刻理解優(yōu)先級鏈之后,就很容易想出針對前面提出的第二個和第三個問題的優(yōu)雅解決方案了。那就是,利用描述符實現(xiàn)一個只讀屬性將變成實現(xiàn)數(shù)據(jù)描述符這個簡單的情況了,即不帶set方法的描述符。盡管在本例中不重要,定義訪問方式的問題只需要在get和set方法中增加所需的功能即可。類屬性每次我們想使用描述符的時候都不得不定義描述符類,這樣看起來非常繁瑣。Python特性提供了一種簡潔的方式用來向?qū)傩栽黾訑?shù)據(jù)描述符。一個屬性簽名如下所示:property(fget=None,fset=None,fdel=None,doc=None)->propertyattributefget、fset和fdel分別是類的getter、setter和r方法。我們通過下面的一個示例來說明如何創(chuàng)建屬性:classAccout(object):self._acct_num=Nonedefget_acct_num(self):returnself._acct_numdefset_acct_num(self,value):self._acct_num=valuedefdel_acct_num(self):delself._acct_numacct_num=property(get_acct_num,set_acct_num,del_acct_num,"Accountnumberproperty.")如果acct是Account的一個實例,acct.acct_num將會調(diào)用getter,acct.acct_num=value將調(diào)用setter,delacct_num.acct_num將調(diào)用r。在Python中,屬性對象和功能可以像《描述符指南》中說明的那樣使用描述符協(xié)議來實現(xiàn),如下所示:classProperty(object):"EmulatePyProperty_Type()inObjects/descrobject.c"definit(self,fget=None,fset=None,fdel=None,doc=None):self.fget=fgetself.fset=fsetself.fdel=fdeldoc=fget.docself.doc=docdefget(self,obj,objtype=None):returnselfraiseAttributeError("unreadableattribute")returnself.fget(obj)defset(self,obj,value):raiseAttributeError("cantsetattribute")self.fset(obj,value)def(self,obj):ifself.fdelisNone:raiseAttributeError("cantattribute")self.fdel(obj)defgetter(self,fget):returntype(self)(fget,self.fset,self.fdel,self.__doc)defsetter(self,fset):returntype(self)(self.fget,fset,self.fdel,self.__doc)defr(self,fdel):returntype(self)(self.fget,self.fset,fdel,self.__doc)Python也提供了@property裝飾器,可以用它來創(chuàng)建只讀屬性。一個屬性對象擁有g(shù)etter、setter和r裝飾器方法,可以使用它們通過對應(yīng)的被裝飾函數(shù)的accessor函數(shù)創(chuàng)建屬性的拷貝。下面的例子最好地解釋了這一點:classC(object):@property#thexproperty.thedecoratorcreatesaread-onlypropertydefx(self):returnself._x@x.setter#thexpropertysettermakesthepropertywriteabledefx(self,value):self._x=value@x.rdefx(self):delself._x如果我們想讓屬性只讀,那么我們可以去掉setter方法。在Python語言中,描述符有著廣泛的應(yīng)用。Python函數(shù)、類方法、靜態(tài)方法都是非數(shù)據(jù)描述符的例子。針對列舉的Python對象是如何使用描述符實現(xiàn)的問題,《描述符指南》給出了一個基本的描述。這些方法有

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論