__getattr__使用

正文

__getattr__函數(shù)的作用: 如果屬性查找(attribute lookup)在實(shí)例以及對(duì)應(yīng)的類中(通過(guò)__dict__)失敗减噪, 那么會(huì)調(diào)用到類的__getattr__函數(shù), 如果沒(méi)有定義這個(gè)函數(shù)慎璧,那么拋出AttributeError異常朴肺。由此可見酒来,__getattr__一定是作用于屬性查找的最后一步,兜底床玻。

我們來(lái)看幾個(gè)例子:

第一個(gè)例子赏陵,很簡(jiǎn)單但經(jīng)典,可以像訪問(wèn)屬性一樣訪問(wèn)dict中的鍵值對(duì)买乃。

class ObjectDict(dict):
    def __init__(self, *args, **kwargs):
        super(ObjectDict, self).__init__(*args, **kwargs)

    def __getattr__(self, name):
        value =  self[name]
        if isinstance(value, dict):
            value = ObjectDict(value)
        return value

if __name__ == '__main__':
    od = ObjectDict(asf={'a': 1}, d=True)
    print od.asf
    print od.asf.a
    print od.d
image.png

第二個(gè)例子姻氨,對(duì)象屬性的lazy initialize。

class WidgetShowLazyLoad(object):
    def fetch_complex_attr(self, attrname):
        '''可能是比較耗時(shí)的操作剪验, 比如從文件讀取'''
        return attrname

    def __getattr__(self, name):
        if name not in self.__dict__:
             self.__dict__[name] = self.fetch_complex_attr(name) 
        return self.__dict__[name]

if __name__ == '__main__':
    w = WidgetShowLazyLoad()
    print 'before', w.__dict__
    a=w.lazy_loaded_attr
    print 'after', w.__dict__
image.png

可以看到肴焊,屬性訪問(wèn)前對(duì)象中的__dict__沒(méi)有任何元素,訪問(wèn)之后就有添加功戚。

這個(gè)例子是類實(shí)例的屬性的惰性初始化娶眷,bottle里面也有一個(gè)用descriptor實(shí)現(xiàn)類屬性的惰性初始化。

import functools
class lazy_attribute(object):
    """ A property that caches itself to the class object. """

    def __init__(self, func):
        functools.update_wrapper(self, func, updated=[])
        self.getter = func

    def __get__(self, obj, cls):
        value = self.getter(cls)
        setattr(cls, self.__name__, value)
        return value

class Widget(object):
    @lazy_attribute
    def complex_attr_may_not_need(clz):
        print 'complex_attr_may_not_need is needed now'
        return sum(i*i for i in range(1000))

if __name__ == '__main__':
    print Widget.__dict__.get('complex_attr_may_not_need') 
    Widget.complex_attr_may_not_need 
    print Widget.__dict__.get('complex_attr_may_not_need') 
image.png

第三個(gè)例子啸臀,我覺(jué)的是最實(shí)用的届宠,__getattr__使得實(shí)現(xiàn)adapter wrapper模式非常容易,我們都知道“組合優(yōu)于繼承”乘粒,__getattr__實(shí)現(xiàn)的adapter就是以組合的形式豌注。

class adaptee(object):
    def foo(self):
        print 'foo in adaptee'
    def bar(self):
        print 'bar in adaptee'

class adapter(object):
    def __init__(self):
        self.adaptee = adaptee()

    def foo(self):
        print 'foo in adapter'
        self.adaptee.foo()

    def __getattr__(self, name):
        print 'name',name
        return getattr(self.adaptee, name)

if __name__ == '__main__':
    a = adapter()
    a.foo()
    a.bar()
image.png

如果adapter需要修改adaptee的行為,那么定義一個(gè)同名的屬性就行了谓厘,其他的想直接“繼承”的屬性幌羞,通通交給__getattr__就行了

最后一個(gè)例子,實(shí)際用到__getattr__竟稳,本質(zhì)上和第三個(gè)例子差不多

class AlgoImpA(object):
    def __init__(self):
        self.obj_attr = 'obj_attr in AlgoImpA'

    def foo(self):
        print 'foo in AlgoImpA'

    def bar(self):
        print 'bar in AlgoImpA'

class AlgoImpB(object):
    def __init__(self):
        self.obj_attr = 'obj_attr in AlgoImpB'

    def foo(self):
        print 'foo in AlgoImpB'

    def bar(self):
        print 'bar in AlgoImpB'

class Algo(object):
    def __init__(self):
        self.imp_a = AlgoImpA()
        self.imp_b = AlgoImpB()
        self.cur_imp = self.imp_a

    def switch_imp(self):
        if self.cur_imp == self.imp_a:
            self.cur_imp = self.imp_b
        else:
            self.cur_imp = self.imp_a

    def __str__(self):
        return 'Algo with imp %s' % str(self.cur_imp)


    def __getattr__(self, name):
        return getattr(self.cur_imp, name)


if __name__ == '__main__':
    algo = Algo()
    
    print algo
    print algo.obj_attr
    algo.foo()
    
    algo.switch_imp()
    
    print algo
    print algo.obj_attr
    algo.bar()
image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末属桦,一起剝皮案震驚了整個(gè)濱河市熊痴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌聂宾,老刑警劉巖果善,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異系谐,居然都是意外死亡巾陕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門纪他,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鄙煤,“玉大人,你說(shuō)我怎么就攤上這事茶袒√莞眨” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵薪寓,是天一觀的道長(zhǎng)亡资。 經(jīng)常有香客問(wèn)我,道長(zhǎng)向叉,這世上最難降的妖魔是什么锥腻? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮母谎,結(jié)果婚禮上瘦黑,老公的妹妹穿的比我還像新娘。我一直安慰自己销睁,他們只是感情好供璧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布存崖。 她就那樣靜靜地躺著冻记,像睡著了一般。 火紅的嫁衣襯著肌膚如雪来惧。 梳的紋絲不亂的頭發(fā)上冗栗,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音供搀,去河邊找鬼隅居。 笑死,一個(gè)胖子當(dāng)著我的面吹牛葛虐,可吹牛的內(nèi)容都是我干的胎源。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼屿脐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼涕蚤!你這毒婦竟也來(lái)了宪卿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤万栅,失蹤者是張志新(化名)和其女友劉穎佑钾,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烦粒,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡休溶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扰她。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兽掰。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖徒役,靈堂內(nèi)的尸體忽然破棺而出禾进,到底是詐尸還是另有隱情,我是刑警寧澤廉涕,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布泻云,位于F島的核電站,受9級(jí)特大地震影響狐蜕,放射性物質(zhì)發(fā)生泄漏宠纯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一层释、第九天 我趴在偏房一處隱蔽的房頂上張望婆瓜。 院中可真熱鬧,春花似錦贡羔、人聲如沸廉白。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)猴蹂。三九已至,卻和暖如春楣嘁,著一層夾襖步出監(jiān)牢的瞬間磅轻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工逐虚, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留聋溜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓叭爱,卻偏偏與公主長(zhǎng)得像撮躁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子买雾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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