小白學(xué)Python之第十四天

定制類

寫在前面:看到類似__slots__這樣形如__xxx__的變量或者函數(shù)名就要注意烈疚,這些在python中是有特殊用途的。

__slots__上文已講過如何運(yùn)用聪轿,__len__()方法我們也知道是為了讓class作用于len()函數(shù)爷肝。

除此之外,python的class中還有許多這樣的特殊用途的函數(shù)屹电,可以幫助我們定制類阶剑。

__str__

引子:我們先定義一個(gè)Student類,打印出一個(gè)實(shí)例:

但打印結(jié)果是這樣的:

這樣帶一長(zhǎng)串不好看危号,所以這時(shí)候我們來定定義__str__()方法牧愁,返回我們想要的它顯示的結(jié)果。

但當(dāng)我們直接賦值變量外莲,不用print時(shí)猪半,這時(shí)在打印出結(jié)果,

和第一次我們打印出的結(jié)果一樣偷线,這是因?yàn)橹苯语@示的變量調(diào)用的不是__str__()磨确,而是__repr__(),區(qū)別是__str__()返回用戶看到的字符串声邦,而__repr__()返回程序開發(fā)者看到的字符串乏奥,也就是說,__repr__()是為調(diào)試服務(wù)的亥曹。解決辦法是再定義一個(gè)__repr__()邓了。但是通常__str__()和__repr__()代碼都是一樣的恨诱,所以,有個(gè)偷懶的寫法:

__iter__

如果一個(gè)類想被用于for......in.....循環(huán)骗炉,類似list或tuple那樣照宝,就必須實(shí)現(xiàn)一個(gè)__iter__()方法,該方法返回一個(gè)迭代對(duì)象句葵,然后厕鹃,Python的for的循環(huán)就會(huì)不斷調(diào)用該迭代對(duì)象的__next__()方法拿到循環(huán)的下一個(gè)值,直到遇到StopIteration錯(cuò)誤時(shí)退出循環(huán)乍丈。

舉例:以斐波那契數(shù)列為例剂碴,寫一個(gè)Fib類,可以作用于for循環(huán):

作用于for循環(huán):

__getitem__

Fib實(shí)例雖然可以作用于for循環(huán)诗赌,看起來和list有點(diǎn)像汗茄,但,把它當(dāng)成list來使用還不行铭若,因?yàn)樗荒芟駆ist那樣按照下標(biāo)取出元素洪碳,需要實(shí)現(xiàn)__getitem__()方法:

就可以任意取數(shù)了。

但還是不能實(shí)現(xiàn)list的切片方法叼屠,這時(shí)因?yàn)開_getitem__()傳入的參數(shù)可能是一個(gè)int瞳腌,也可能是一個(gè)切片對(duì)象slice,所以要判斷:

現(xiàn)在就可以切片了

但還有一個(gè)問題就是不能對(duì)step參數(shù)處理

也不能對(duì)負(fù)數(shù)作處理镜雨,所以嫂侍,要正確實(shí)現(xiàn)一個(gè)__getitem__()還是有很多工作要做的。

此外荚坞,如果把對(duì)象看成dict挑宠,__getitem__()的參數(shù)也可能是一個(gè)可以看做key的object,例如str.

與之對(duì)應(yīng)的是 __setitem__()方法颓影,把對(duì)象視作list或dict來對(duì)集合賦值各淀,最后,還有一個(gè)__deIitem__()方法诡挂,用于刪除某個(gè)元素碎浇。

總之,通過以上方法璃俗,我們可以定義的類表現(xiàn)的和Python自帶的list奴璃、tuple、dict沒什么區(qū)別城豁,這完全歸功于動(dòng)態(tài)語言的“鴨子類型”苟穆,不需要強(qiáng)制繼承某個(gè)接口。

__getattr__

正常情況下,當(dāng)我們調(diào)用類的方法或?qū)傩詴r(shí)鞭缭,如果不存在剖膳,就會(huì)報(bào)錯(cuò)魏颓。當(dāng)調(diào)用不存在的屬性時(shí)就會(huì)出現(xiàn)AttributeError的錯(cuò)誤岭辣,要避免這個(gè)錯(cuò)誤,我們可以在加上這個(gè)沒有的屬性甸饱,除了這個(gè)方法外沦童,我們還可以有另一個(gè)方法,那就是寫一個(gè)__getattr__()方法叹话,動(dòng)態(tài)返回一個(gè)屬性偷遗,示例如下:

返回函數(shù)也是可以的:

只是調(diào)用方式要變:

注意:只有在沒有找到屬性的情況下,才調(diào)用__getattr__驼壶,已有屬性氏豌,不會(huì)在__getattr__中查找。此外热凹,我們?cè)谌我庹{(diào)用時(shí)都會(huì)返回None,這是因?yàn)槲覀兌x的__getattr__默認(rèn)返回的就是None泵喘。要讓class只相應(yīng)特定的幾個(gè)屬性,我們就要按照約定般妙,拋出AttributeError的錯(cuò)誤:

運(yùn)行下:

這實(shí)際上是把一個(gè)類的所有屬性和方法調(diào)用都全部動(dòng)態(tài)化處理了纪铺,不需要任何特殊手段。

作用:可以針對(duì)完全動(dòng)態(tài)的情況做調(diào)用碟渺。

舉例:現(xiàn)在很多網(wǎng)站都搞REST API, 比如新浪微博鲜锚、豆瓣等,如果要寫SDK苫拍,給每個(gè)URL對(duì)應(yīng)的API都都寫一個(gè)方法芜繁,那就累死了,API一旦改動(dòng)绒极,SDK就要改骏令。利用完全動(dòng)態(tài)的__getattr__就可以寫出一個(gè)鏈?zhǔn)秸{(diào)用:

試試用print打印出來:

返回原理是這樣的:

__call__

當(dāng)我們?cè)谡{(diào)用實(shí)例方法時(shí),用instance.method()來調(diào)用集峦。能不能直接在實(shí)例本身調(diào)用那伏社,答案是可以的,只需要用__call__()方法塔淤。舉例如下:

調(diào)用:

__call__()還可以定義參數(shù)摘昌。對(duì)實(shí)例進(jìn)行直接調(diào)用就好比對(duì)一個(gè)函數(shù)調(diào)用,所以你完全可以把對(duì)象看成函數(shù)高蜂,把函數(shù)看成對(duì)象聪黎,因?yàn)閮烧弑緛砭蜎]有本質(zhì)的區(qū)別。

如果把對(duì)象看成函數(shù),那么函數(shù)本身是可以在運(yùn)行期動(dòng)態(tài)創(chuàng)建出來的稿饰,因?yàn)轭惖膶?shí)例都是運(yùn)行期創(chuàng)建出來的锦秒。這么一來,我們就模糊了對(duì)象和函數(shù)的界限喉镰。

那么旅择。我們?nèi)绾闻袛嘁粋€(gè)變量是對(duì)象還是函數(shù),其實(shí)侣姆,我們只要判斷他是否能被調(diào)用就可以了生真,能被調(diào)用的就是一個(gè)Callable()對(duì)象,通過callable()我們就可以判斷一個(gè)對(duì)象是否能被調(diào)用捺宗。

總結(jié):

完全動(dòng)態(tài)調(diào)用特性:把一個(gè)類的所有屬性和方法調(diào)用全部動(dòng)態(tài)化處理?

?__call__(): 用于實(shí)例自身的調(diào)用柱蟀,達(dá)到()調(diào)用的效果 , 即可以把此類的對(duì)象當(dāng)作函數(shù)來使用蚜厉,相當(dāng)于重載了括號(hào)運(yùn)算符??

__getattr__(): 當(dāng)調(diào)用不存在的屬性時(shí)調(diào)用此方法來嘗試獲得屬性

鏈?zhǔn)竭\(yùn)行過程:

分析

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末长已,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子昼牛,更是在濱河造成了極大的恐慌术瓮,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匾嘱,死亡現(xiàn)場(chǎng)離奇詭異斤斧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)霎烙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門撬讽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人悬垃,你說我怎么就攤上這事游昼。” “怎么了尝蠕?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵烘豌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我看彼,道長(zhǎng)廊佩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任靖榕,我火速辦了婚禮标锄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘茁计。我一直安慰自己料皇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著践剂,像睡著了一般鬼譬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逊脯,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天优质,我揣著相機(jī)與錄音,去河邊找鬼男窟。 笑死盆赤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的歉眷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼颤枪,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼汗捡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起畏纲,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤扇住,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后盗胀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艘蹋,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年票灰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了女阀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡屑迂,死狀恐怖浸策,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情惹盼,我是刑警寧澤庸汗,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站手报,受9級(jí)特大地震影響蚯舱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜掩蛤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一枉昏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盏档,春花似錦凶掰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽前翎。三九已至,卻和暖如春畅涂,著一層夾襖步出監(jiān)牢的瞬間港华,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工午衰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留立宜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓臊岸,卻偏偏與公主長(zhǎng)得像橙数,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子帅戒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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