Python面向?qū)ο箢愋椭械哪Хǚ椒ㄊ崂碚偎唬偨Y(jié)

這里只分析幾個(gè)可能會(huì)常用到的魔法方法父晶,想new這種不常用的,用來做元類初始化的或者是init這種初始化使用的 弄跌,每個(gè)人都會(huì)用的就不介紹了甲喝。

其實(shí)每個(gè)魔法方法都是在對(duì)內(nèi)建方法的重寫,和做像裝飾器一樣的行為铛只。理解這個(gè)道理埠胖,嘗試去理解每個(gè)細(xì)節(jié)裝飾器會(huì)比較方便。

1.關(guān)于strrepr:

    def __init__(self, world):
        self.world = world

    def __str__(self):
        return 'world is %s str' % self.world

    def __repr__(self):
        return 'world is %s repr' % self.world

t = Test('world_big')
print str(t)
print repr(t)

output:

world is world_big str
world is world_big repr

其實(shí) str相當(dāng)去是str()方法 而repr相當(dāng)于repr()方法淳玩。str是針對(duì)于讓人更好理解的字符串格式化直撤,而repr是讓機(jī)器更好理解的字符串格式化

其實(shí)獲得返回值的方法也很好測(cè)試,在我們平時(shí)使用python的時(shí)候蜕着,在不適用print直接輸出對(duì)象的時(shí)候谋竖,通常調(diào)用的就是repr方法红柱,這個(gè)時(shí)候改寫repr方法可以讓他方便的輸入我們想要知道的內(nèi)容,而不是一個(gè)默認(rèn)內(nèi)容蓖乘。

2.關(guān)于hashdir:

其實(shí)在實(shí)際應(yīng)用中锤悄,這兩個(gè)用到的頻率并不高,但是在有些庫(kù)里面是有看到過
hash是hash()方法的裝飾器版本嘉抒,而dir是dir()的裝飾器版本零聚。

class Test(object):
    def __init__(self, world):
        self.world = world


x = Test('world')
p = Test('world')
print hash(x) == hash(p)
print hash(x.world) == hash(p.world)


class Test2(object):
    def __init__(self, song):
        self.song = song

    def __hash__(self):
        return 1241

x = Test2('popo')
p = Test2('janan')

print x, hash(x)
print p, hash(p)

output:

False
True
<__main__.Test2 object at 0x101b0c590> 1241
<__main__.Test2 object at 0x101b0c4d0> 1241

可以看到這里的hash()方法總是會(huì)返回int型的數(shù)字,可以用于比較一個(gè)唯一的對(duì)象些侍,比方說一個(gè)不同內(nèi)存的object不會(huì)相當(dāng)隶症,而相同字符串hash之后就會(huì)相等,然后我們通過修改hash方法來修改hash函數(shù)的行為岗宣,讓他總是返回1241蚂会,也是可以輕松做到的,耗式。

另外一個(gè)方法是dir()颂龙,熟悉python的人都知道dir()可以讓我們查看當(dāng)前環(huán)境下有哪些方法和屬性可以進(jìn)行調(diào)用,如果我們使用dir(object)語法纽什,可以獲得一個(gè)對(duì)象擁有的方法和屬性措嵌,同樣的道理如果我們?cè)陬愔卸x了dir(),就可以指定哪些方法和屬性能夠被dir()方法所查看查找到。

3.關(guān)于控制參數(shù)訪問的getattr芦缰,setattr企巢,delattrgetattribute:

getattr是一旦我們嘗試訪問一個(gè)并不存在的屬性的時(shí)候就是調(diào)用让蕾,而如果這個(gè)屬性存在則不會(huì)調(diào)用該方法浪规。
來看一個(gè)getattr的例子:

    def __init__(self, world):
        self.world = world

    def __getattr__(self, item):
        return item


x = Test('world123')
print x.world4

output:
world4

這里我們并沒有world4屬性,在找不到屬性的情況下探孝,正常的繼承object的對(duì)象都會(huì)拋出AtrribuError的錯(cuò)誤笋婿,但是這里我通過getattr魔法方法改變了找不到屬性時(shí)候的類的行為,輸出了查找的屬性的參數(shù)顿颅。

setattr是設(shè)置參數(shù)的時(shí)候會(huì)調(diào)用到的魔方方法缸濒,相當(dāng)于設(shè)置參數(shù)錢的有個(gè)鉤子,每個(gè)設(shè)置屬性的方法都繞不開這個(gè)魔方方法粱腻,只有擁有這個(gè)魔方方法的對(duì)象才可以設(shè)置屬性庇配,在使用這個(gè)方法的時(shí)候要特別注意到不要被循環(huán)調(diào)用了,
下面來看一個(gè)例子:

    def __init__(self, world):
        self.world = world

    def __setattr__(self, name, value):
        if name == 'value':
            object.__setattr__(self, name, value - 100)
        else:
            object.__setattr__(self, name, value)

x = Test(123)
print x.world
x.value = 200
print x.value

output:
123
100

這里我們先初始化一個(gè)Test類的實(shí)例x绍些,通過init方法我們可以注意到捞慌,會(huì)給初始化的world參數(shù)進(jìn)行賦值。這里的self.world = world語句就是在做這個(gè)事情柬批。

注意啸澡,這里在進(jìn)行world參數(shù)賦值的時(shí)候袖订,就是會(huì)調(diào)用到setattr方法。這個(gè)例子來看world就是name嗅虏,而后面的值的world就是value著角。我在setattr里面做了一個(gè)行為改寫,我將判斷name 值是'value'的進(jìn)行特殊處理旋恼,把它的value值減少100. 所以輸出了預(yù)期的結(jié)果。

我為什么說setattr特別容易出現(xiàn)循環(huán)調(diào)用奄容?因?yàn)槿魏钨x值方法都會(huì)走這個(gè)魔法方法冰更,如果你在你改寫setattr方法里面使用了類似的賦值,又回循環(huán)調(diào)用回setattr方法昂勒。例如

class Test(object):
    def __init__(self, world):
        self.world = world

    def __setattr__(self, name, value):
        self.name = value


x = Test(123)
print x.world

output:
RuntimeError: maximum recursion depth exceeded

這里我們想讓setattr執(zhí)行默認(rèn)行為蜀细,也就是將value賦值給name,和object對(duì)象中的同樣方法戈盈,做類似的操作奠衔。但是這里我們不調(diào)用父類setattr的方法來實(shí)現(xiàn),做這樣的嘗試得到的結(jié)果就是塘娶,超過循環(huán)調(diào)用深度归斤,報(bào)錯(cuò)。因?yàn)檫@里在執(zhí)行初始化方法self.world = world的時(shí)候刁岸,就會(huì)調(diào)用setattr方法脏里,而這里的setattr方法里面的self.name = value又會(huì)調(diào)用自身。所以造成了循環(huán)調(diào)用虹曙。所以使用該魔法方法的時(shí)候要特別注意迫横。

delattr的行為和setattr特別相似,同樣需要注意的也是循環(huán)調(diào)用問題酝碳,其他都差不多矾踱,只是把屬性賦值變成了 del self.name這樣的表示。下面直接上個(gè)例子疏哗,不再多贅述呛讲。

    def __init__(self, world):
        self.world = world

    def __delattr__(self, item):
        print 'hahaha del something'
        object.__delattr__(self, item)


x = Test(123)
del x.world
print x.world

output:

hahaha del something
Traceback (most recent call last):
File "/Users/piperck/Desktop/py_pra/laplace_pra/practie_01_23/c2.py", line 12, in <module>
print x.world
AttributeError: 'Test' object has no attribute 'world'

可以看到我們將屬性刪除之后,就找不到那個(gè)屬性了返奉。但是在刪除屬性的時(shí)候調(diào)用了delattr圣蝎,我在里面打印了一段話,在執(zhí)行之前被打印出來了

getattributegetattr方法唯一不同的地方是衡瓶,上面我們已經(jīng)介紹了getattr方法只能在找不到屬性的時(shí)候攔截調(diào)用徘公,然后進(jìn)行重載或者加入一些其他操作。但是getattribute更加強(qiáng)大哮针,他可以攔截所有的屬性獲取关面。所以也容易出現(xiàn)我們上面提到的坦袍,循環(huán)調(diào)用的問題。下面上一個(gè)例子來說明這個(gè)問題:

class Test(object):
    def __init__(self, world):
        self.world = world

    def __getattribute__(self, item):
        print 'get_something: %s' % item
        return item


x = Test(123)
print x.world
print x.pp

output:
get_something: world
world
get_something: pp
pp

可以看到等太,區(qū)別于getattr只攔截不存在的屬性捂齐,getattribute會(huì)攔截所有的屬性。所以導(dǎo)致了已經(jīng)被初始化的world值123缩抡,也被改寫成了字符串world奠宜。而不存在的屬性也被改寫了成了pp。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瞻想,一起剝皮案震驚了整個(gè)濱河市压真,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蘑险,老刑警劉巖滴肿,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異佃迄,居然都是意外死亡泼差,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門呵俏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堆缘,“玉大人,你說我怎么就攤上這事普碎√灼。” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵随常,是天一觀的道長(zhǎng)潜沦。 經(jīng)常有香客問我,道長(zhǎng)绪氛,這世上最難降的妖魔是什么唆鸡? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮枣察,結(jié)果婚禮上争占,老公的妹妹穿的比我還像新娘。我一直安慰自己序目,他們只是感情好臂痕,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著猿涨,像睡著了一般握童。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上叛赚,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天澡绩,我揣著相機(jī)與錄音稽揭,去河邊找鬼。 笑死肥卡,一個(gè)胖子當(dāng)著我的面吹牛溪掀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播步鉴,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼揪胃,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了氛琢?” 一聲冷哼從身側(cè)響起喊递,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎艺沼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蕴掏,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡障般,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盛杰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挽荡。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖即供,靈堂內(nèi)的尸體忽然破棺而出定拟,到底是詐尸還是另有隱情,我是刑警寧澤逗嫡,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布青自,位于F島的核電站,受9級(jí)特大地震影響驱证,放射性物質(zhì)發(fā)生泄漏延窜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一抹锄、第九天 我趴在偏房一處隱蔽的房頂上張望逆瑞。 院中可真熱鬧,春花似錦伙单、人聲如沸获高。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽念秧。三九已至,卻和暖如春布疼,著一層夾襖步出監(jiān)牢的瞬間出爹,已是汗流浹背庄吼。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留严就,地道東北人总寻。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像梢为,于是被迫代替她去往敵國(guó)和親渐行。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

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

  • 字符串格式化調(diào)用方法 —— format 通過創(chuàng)建字符串模板铸董,利用format函數(shù)祟印,替代相應(yīng)的值。 可以通過絕對(duì)位...
    plutoese閱讀 1,523評(píng)論 0 47
  • python 魔術(shù)方法 前言 在做python開發(fā)的過程中,我們大家都會(huì)遇到在class(類)中使用雙下劃線的方法...
    shu_ke閱讀 451評(píng)論 1 2
  • 天機(jī)神算子閱讀 189評(píng)論 0 0
  • 又到半個(gè)月探望一次兒子的時(shí)間了粟害。我拎著兒子電話囑咐我要帶的東西蕴忆,走進(jìn)了他們宿舍。 宿舍里到處是人悲幅,...
    婉葉老師閱讀 977評(píng)論 5 18
  • 獨(dú)自站在大道中央套鹅, 看四通八達(dá)的路向著前方, 孤單感到迷茫 我又...
    塵霞閱讀 269評(píng)論 0 2