Python之管理屬性

學(xué)習(xí)一下幾個內(nèi)容

  • __getattr__和__setattr__方法,把未定義的屬性獲取和所有的屬性賦值指向通用的處理器方法
  • __getattribute__方法纤房,把所有屬性都指向Python3.0中類的一個泛型處理器的方法
  • property內(nèi)置函數(shù)鹃骂,把特定屬性訪問定位到get和set處理函數(shù)笨腥,也叫做特性(Property)
  • 描述符協(xié)議撩独,把特定屬性訪問定位到具有任意get和set處理器方法的類的實例

特性協(xié)議允許我們把一個特定屬性的get和set操作指向我們所提供的函數(shù)或方法校读,使得我們能夠插入在屬性訪問的時候自動運行代碼。

*基礎(chǔ)知識

attribute = property(fget,fset,fdel,doc)
四個參數(shù)分別代表屬性attribute的get丧靡,set蟆沫,del方法和文檔性信息

#-*-coding:UTF-8-*-
class Person:
    def __init__(self,name):
        self._name = name
    def getName(self):
        print('fetch...')
        return self._name
    def setName(self,value):
        self._name = value
        print('change...')
    def delName(self):
        print('remove...')
        del self._name
    name = property(getName,setName,delName,'name property docs')  #屬性name是通過property內(nèi)置函數(shù)創(chuàng)建的并提供一些方法操作name的值
if __name__ == '__main__':
    bob = Person('Bob Smith')
    print(bob.name)     #調(diào)用getName方法 獲取name的值
    bob.name = 'Robert Smth'  #調(diào)用setName方法設(shè)置值
    print(bob.name)
    del bob.name
    print(Person.name.__doc__)
####
fetch...
Bob Smith
change...
fetch...
Robert Smth
remove...
name property docs
[Finished in 0.3s]

像所有的類屬性一樣,實例和較低的子類都繼承特性温治。

class Coder(Person):
    pass
if __name__ == '__main__':
    bob = Coder('Bob Smith')
    print(bob.name)
###
fetch...
Bob Smith
Coder子類從Person繼承了name特性

計算屬性

class PropSquare:
    def __init__(self, start):
        self.value = start
    def getX(self):
        return self.value**2
    def setX(self,value):
        self.value = value
    X = property(getX,setX)
if __name__ == '__main__':
    P = PropSquare(3)
    Q = PropSquare(32)
    print(P.X)
    P.X = 4
    print(P.X)
    print(Q.X)
###
9
16
1024
說明可以在自定義的函數(shù)中做一些數(shù)據(jù)方面的處理

使用裝飾器來編寫特性

#-*-coding:UTF-8-*-
"""
@decorator
def func(args):...

相當于
def func(args):...
func = decorator(func)
"""
class Person:
    def __init__(self, name):
        self._name = name
    @property
    def name(self):
        """name property docs"""
        print('fetch.....')
        return self._name

    @name.setter
    def name(self,value):
        print('change')
        self._name = value
    @name.deleter
    def name(self):
        print('remove...')
        del self._name
if __name__ == '__main__':
    rose = Person('Rose Jhon')
    print(rose.name)
    rose.name = 'Roose Jhon'
    print(rose.name)
    del rose.name
###
fetch.....
Rose Jhon
change
fetch.....
Roose Jhon
remove...
裝飾是編寫特性的替代方法饭庞。注意set和del方法的裝飾

描述符

描述符提供了攔截屬性訪問的一種替代方法。特性是描述符的一種熬荆,property內(nèi)置函數(shù)是創(chuàng)建一個特定類型描述符的一種簡化方法舟山。
描述符協(xié)議允許特性我們把一個特定屬性的get和set操作指向我們提供的一個單獨類對象的方法:他們提供了一種方式插入在訪問屬性的時候自動運行的代碼,并且他們允許我們攔截屬性刪除并且為屬性提供文檔卤恳。描述符作為獨立的類創(chuàng)建累盗,并且他們就像方法函數(shù)一樣分配給類屬性,也可以通過子類和實例繼承
*基礎(chǔ)知識

class Descriptor:
    def __get__(self,instance,owner):...
    def __set__(self,instance,value):...
    def __delete__(self,instance):.....

帶有這些方法的類都可以看做是描述符突琳,并且當他們的一個實例分配給另一個類的屬性的時候幅骄,它們的這些方法是特殊的----當訪問屬性的時候,會自動調(diào)用它們本今。
描述符參數(shù):都傳遞了描述符類實例(self)以及描述符實例所附加的客戶類的實例(instance)。__get__訪問方法還額外的接收一個owner參數(shù)主巍,指定描述符實例要附加到的類冠息。

#-*-coding:UTF-8-*-
"""
描述符
"""
class Name:
    def __get__(self,instance,owner):
        print(self,instance,owner)
        return instance._name
    def __set__(self,instance,value):
        print('change')
        instance._name = value
    def __delete__(self,instance):
        print('remove')
        del instance._name
"""
描述符生成的屬性
"""
class Person:
    def __init__(self,name):
        self._name = name
    name = Name()
"""
self是Name類的實例
instance是Person類的實例
owner是Person類
"""
if __name__ == '__main__':
    bob = Person('Jim Green')
    print(bob.name)
    bob.name = 'Jam Green'
    del bob.name
###
<__main__.Name object at 0x00610FB0> <__main__.Person object at 0x00610FD0> <class '__main__.Person'>
Jim Green
change
remove

描述符的計算屬性

計算屬性

class DescSquare:
    def __init__(self,start):
        self.value = start
    def __get__(self,instance,owner):
        return self.value**2
    def __set__(self,instance,value):
        self.value = value
class Client1:
    X = DescSquare(3) #類屬性 所有實例共享的  描述符類實例化的時候傳值
if __name__ == '__main__':
    c1 = Client1()
    print(c1.X)
    print(Client1.X)

在描述符中使用狀態(tài)信息

  • 描述符狀態(tài)用來管理內(nèi)部用于描述符工作的數(shù)據(jù)
  • 實例狀態(tài)記錄了和客戶類相關(guān)的信息,以及可能有客戶類創(chuàng)建的信息
"""
描述符狀態(tài)信息
"""
class DescState:
    def __init__(self,value):
        self.value = value
    def __get__(self,instance,owner):
        print('DescState get')
        return self.value*10
    def __set__(self,instance,value):
        print('DescState set')
        self.value = value
class CalcAttrs:
    X = DescState(2)
    Y = 3
    def __init__(self):
        self.Z = 4
if __name__ == '__main__':
    obj = CalcAttrs()
    print(obj.X,obj.Y,obj.Z)
####
value屬性僅存在描述符中孕索,在CalcAttrs中使用value也不會沖突

對描述符存儲或使用附加到客戶類的實例的一個屬性逛艰,不是描述符類的屬性

class InsState:
    def __get__(self,instance,owner):
        print('InsState get')
        return instance._Y*100
    def __set__(self,instance,value):
        print('InsState set')
        instance._Y = value
class CalcAttrs1:
    X = DescState(2)
    Y = InsState()
    def __init__(self):
        self._Y = 3
        self.Z = 4
if __name__ == '__main__':
    obj = CalcAttrs1()
    print(obj.X,obj.Y,obj.Z)
###
DescState get
InsState get
20 300 4
在運行的時候 會傳遞CalcAttrs1類的實例過去(instance)
在描述符類中instance._Y調(diào)用的就是obj的屬性。在obj.Y的時候 會調(diào)用 InsState實例Y中的__get__方法并傳遞相關(guān)參數(shù)過去

__getattr__和__getattribute__

  • __getattr__針對未定義的屬性運行----也就是說搞旭,屬性沒有存儲在實例上散怖,或者沒有從父類之一繼承
  • __getattribute__針對每個屬性菇绵,當使用時,需要小心避免通過把屬性訪問傳遞給超類而導(dǎo)致遞歸循環(huán)
def __getattr__(self,name): #On undefined attribute fetch [obj.name]
def __getattribute__(self,name):#on all attribute fetch [obj.name]
def __setattr__(self,name,value):#on all attribute assignment [obj.name=value]
def __delattr__(self,name): #on all attribute deletion [del obj.name]
其中self通常是主體實例對象镇眷,name是將要訪問的屬性的字符串咬最,value是要賦給該屬性的對象

例子

#-*-coding:UTF-8-*-
class Catcher:
    def __getattr__(self,name):
        print('Get:',name)
    def __setattr__(self,name,value):
        print('Set:',name,value)
    def test(slef):
        print('test')
class Wrapper:
    def __init__(self,obj):
        self.wrapper = obj
    def __getattr__(self,attrname):
        print('Trace:',attrname)
        return getattr(self.wrapper,attrname)
if __name__ == '__main__':
    X = Catcher()
    X.job
    X.pay = 99
    Y = Wrapper(X)
    Y.test()
###
Get: job
Set: pay 99
Trace: test
test
####
Catcher的實例X在調(diào)用X.job時,會遭到getattr方法的攔截(攔截沒有定義的屬性)

注意使用__setattr__和__getattribute__要避免循環(huán)

#-*-coding:UTF-8-*-
class Person:
    def __init__(self,name):
        self._name = name
    # def __getattr__(self,attr):
    #   if attr == 'name':
    #       print('fetch....')
    #       return self._name
    #   else:
    #       raise AttributeError(attr)
    def __getattribute__(self,attr):
        if attr == 'name':
            print('fetch')
            attr = '_name'
        return object.__getattribute__(self,attr)
    def __setattr__(self,attr,value):
        if attr=='name':
            print('change...')
            attr = '_name'
        print(attr)
        self.__dict__[attr] = value   #避免循環(huán) 如果使用self._name = value會產(chǎn)生遞歸循環(huán)
    def __delattr__(self,attr):
        if attr == 'name':
            print('remove...')
            attr = '_name'
        del self.__dict__[attr]
if __name__ == '__main__':
    bob = Person('Bob Smith')
    print(bob.name)
    bob.name = 'Robert Smith'
    print(bob.name)
    del bob.name
    print('-'*20)
    sue = Person('Sue Jones')
    print(sue.name)
- 構(gòu)造函數(shù)中的self._name = name會觸發(fā)__setattr__

__getattr__和__getattribute__比較

  • __getattr__攔截未定義的屬性欠动,已經(jīng)定義的屬性不會攔截
  • __getattribute__攔截所有的屬性獲取永乌,并且需要將沒有管理的屬性訪問指向超類獲取器以避免循環(huán)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市具伍,隨后出現(xiàn)的幾起案子翅雏,更是在濱河造成了極大的恐慌,老刑警劉巖人芽,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件望几,死亡現(xiàn)場離奇詭異,居然都是意外死亡萤厅,警方通過查閱死者的電腦和手機橄抹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祈坠,“玉大人害碾,你說我怎么就攤上這事∩饩校” “怎么了慌随?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長躺同。 經(jīng)常有香客問我阁猜,道長,這世上最難降的妖魔是什么蹋艺? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任剃袍,我火速辦了婚禮,結(jié)果婚禮上捎谨,老公的妹妹穿的比我還像新娘民效。我一直安慰自己,他們只是感情好涛救,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布畏邢。 她就那樣靜靜地躺著,像睡著了一般检吆。 火紅的嫁衣襯著肌膚如雪舒萎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天蹭沛,我揣著相機與錄音臂寝,去河邊找鬼章鲤。 笑死,一個胖子當著我的面吹牛咆贬,可吹牛的內(nèi)容都是我干的败徊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼素征,長吁一口氣:“原來是場噩夢啊……” “哼集嵌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起御毅,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤根欧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后端蛆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凤粗,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年今豆,在試婚紗的時候發(fā)現(xiàn)自己被綠了嫌拣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡呆躲,死狀恐怖异逐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情插掂,我是刑警寧澤灰瞻,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站辅甥,受9級特大地震影響酝润,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜璃弄,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一要销、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧夏块,春花似錦疏咐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至患民,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垦梆,已是汗流浹背匹颤。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工仅孩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人印蓖。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓辽慕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親赦肃。 傳聞我的和親對象是個殘疾皇子溅蛉,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 基礎(chǔ)1.r''表示''內(nèi)部的字符串默認不轉(zhuǎn)義2.'''...'''表示多行內(nèi)容3. 布爾值:True、False(...
    neo已經(jīng)被使用閱讀 1,660評論 0 5
  • 裝飾是為函數(shù)和類指定管理代碼的一種方式.裝飾器本身的形式是處理其他的可調(diào)用對象的可調(diào)用的對象他宛。 函數(shù)裝飾器在函數(shù)定...
    低吟淺唱1990閱讀 222評論 0 0
  • 當你已經(jīng)開始了健康正常的生活方式厅各,那么事不宜遲镜撩,進入矯正口吃的第二環(huán)節(jié),那就是對于“思維方式”的培養(yǎng)與形成队塘。 口吃...
    traveLightning閱讀 474評論 2 4
  • 秋意已濃袁梗,情深重。你我走過了冬天憔古,就是春天了遮怜。
    成義隨筆閱讀 200評論 0 0
  • 收納空間允許的情況下,衣服能掛則掛鸿市,這樣既方便收納锯梁,拿取也節(jié)省時間。 折疊真的挺費時間的灸芳,尤其時間緊迫時涝桅,基本只能...
    5d15f86452fc閱讀 1,033評論 0 27