第四十五課:魔法方法:屬性訪問

內(nèi)容來源于網(wǎng)絡(luò)惹盼,本人只是在此稍作整理妄辩,如有涉及版權(quán)問題惑灵,歸小甲魚官方所有。

練習(xí)題(來自小甲魚官方論壇)

0.請問以下代碼的作用是什么眼耀?這樣寫正確嗎英支?(如果不正確,請改正)

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

答:這段代碼試圖在對象的屬性發(fā)生賦值操作的時(shí)候哮伟,將實(shí)際的值+1賦值給相應(yīng)的屬性干花。但這么寫法是錯(cuò)誤的,因?yàn)槊慨?dāng)屬性被賦值的時(shí)候楞黄,__ setattr__()會(huì)被調(diào)用池凄,而里面的self.name = value + 1語句又會(huì)再次觸發(fā)__ setattr__()調(diào)用,導(dǎo)致無限遞歸鬼廓。
正確地寫法:

def __setattr__(self, name, value):
        self.__dict__[name]  =  value + 1

def __setattr__(self, name, value):
        super().__setattr__() =  value + 1

1.自定義該類的屬性被訪問的行為肿仑,你應(yīng)該重寫哪個(gè)魔法方法?

答:__ getattribute__(self, name)


2.在不上機(jī)驗(yàn)證的情況下碎税,你能推斷以下代碼會(huì)顯示什么嗎尤慰?

>>> class C:
    def __getattr__(self, name):
        print(1)
    def __getattribute__(self, name):
        print(2)
    def __setattr__(self, name, value):
        print(3)
    def __delattr__(self, name):
        print(4)

        
>>> c = C()
>>> c.x = 1
# 位置一,請問這里會(huì)顯示什么蚣录?
>>> print(c.x)
#位置二割择,請問這里會(huì)顯示什么?

答:

>>> c = C()
>>> c.x = 1
3
>>> print(c.x)
2
None

位置一會(huì)顯示3萎河,因?yàn)閏.x = 1是賦值操作荔泳,所以會(huì)訪問__ setattr__()魔法辦法;
位置二會(huì)顯示2和None虐杯。因?yàn)閤是屬于實(shí)例對象c的屬性玛歌,所以c.x是訪問一個(gè)存在的屬性,因此會(huì)訪問__ getattribute__()魔法方法擎椰。但是我們重寫了這個(gè)方法支子,使得它不能按照正常的邏輯返回屬性值,而打印一個(gè)2代替达舒。由于我們沒有寫返回值值朋,所以緊接著返回None并被print()打印出來。


3.在不上機(jī)驗(yàn)證的情況下巩搏,你能推斷以下代碼會(huì)顯示什么嗎昨登?

>>> class C:
      def __getattr__(self, name):
          print(1)
          return super().__getattr__(name)
      def __getattribute__(self, name):
          print(2)
          return super().__getattribute__(name)
      def __setattr__(self, name, value):
          print(3)
          super().__setattr__(name, value)
      def __delattr__(self, name):
          print(4)
          super().__delattr__(name)

      
>>> c = C()
      
>>> c.x

答:輸出如下:

>>> c.x
      
2
1
Traceback (most recent call last):
  File "<pyshell#288>", line 1, in <module>
    c.x
  File "<pyshell#286>", line 4, in __getattr__
    return super().__getattr__(name)
AttributeError: 'super' object has no attribute '__getattr__'
>>> 

分析:首先c.x會(huì)調(diào)用__ getattribute__()魔法方法,打印2贯底;然后調(diào)用super().__ getattribute__()丰辣,發(fā)現(xiàn)找不到屬性名x,因此緊接著調(diào)用__ getattr__(),于是打印1笙什;但是飘哨,你猜到了開頭卻猜不到結(jié)局……當(dāng)你希望最后以super().__ getattr__()終了的時(shí)候,Python竟然告訴你AttributeError琐凭,super對象木有__ getattr__Q柯 !
求證:

>>> dir(super)
      
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__self_class__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__thisclass__']

4.請指出以下代碼的問題所在:

>>> class Counter:
    def __init__(self):
        self.counter = 0
    def __setattr__(self, name, value):
        self.counter += 1
    def __delattr__(self, name):
        self.counter -= 1
        super().__delattr__(name)

答:

>>> class Counter:
    def __init__(self):
        self.counter = 0  # 這里會(huì)觸發(fā)__setattr__調(diào)用
    def __setattr__(self, name, value):
#既然需要__setattr__調(diào)用才能真正設(shè)置self.counter的值统屈,所以這個(gè)時(shí)候self.counter還沒有定義摆马,所以沒法+1,錯(cuò)誤的根源
        self.counter += 1
    def __delattr__(self, name):
        self.counter -= 1
        super().__delattr__(name)

修改如下:

>>> class Counter:
    def __init__(self):
        self.counter = 0
    def __setattr__(self, name, value):
        super().__setattr__(name, value+1)
    def __delattr__(self, name):
        self.counter -= 1
        super().__delattr__(name)

        
>>> c = Counter()
>>> c.counter = 1
>>> c.counter
2
>>> c.counter = 2
>>> c.counter
3

編程題

0.按要求重寫魔法方法:訪問一個(gè)不存在的屬性時(shí)鸿吆,不報(bào)錯(cuò)并且提示“該屬性不存在!”

答:

>>> class Demo():
    def __getattr__(self, name):
        return '該屬性不存在述呐!'

    
>>> d = Demo()
>>> d.x
'該屬性不存在惩淳!'

1.編寫Demo類,使得下邊代碼可以正常運(yùn)行:

>>> demo = Demo()
>>> demo.x
'FishC'
>>> demo.x = "X-man"
>>> demo.x
'X-man'

答:

>>> class Demo:
    def __getattr__(self, name):
        self.name = 'FishC'
        return self.name
    
>>> demo = Demo()
>>> demo.x
'FishC'
>>> demo.x = "X-man"
>>> demo.x
'X-man'

2.修改上班第4題乓搬,使之可以正常運(yùn)行思犁;編寫一個(gè)Counter類,用于實(shí)時(shí)檢測對象有多少個(gè)屬性进肯。

程序?qū)崿F(xiàn)如下:

>>> c = Counter()
>>> c.x = 1
>>> c.counter
1
>>> c.y = 1
>>> c.z = 1
>>> c.counter
3
>>> del c.x
>>> c.counter
2

答:

>>> class Counter:
    def __init__(self):
        super().__setattr__('counter', 0)
    def __setattr__(self, name, value):
        super().__setattr__('counter', self.counter + 1)
        super().__setattr__(name, value)
    def __delattr__(self, name):
        super().__setattr__('counter', self.counter - 1)
        super().__delattr__(name)

3.請寫下這一節(jié)課你學(xué)習(xí)到的內(nèi)容:格式不限激蹲,回憶并復(fù)述是加強(qiáng)記憶的好方式!

  • 屬性相關(guān)的魔法方法
魔法方法 含義
__ getattr__(self, name) 定義當(dāng)用戶試圖獲取一個(gè)不存在的屬性時(shí)的行為
__ getattribute__(self, name) 定義當(dāng)該類的屬性被訪問時(shí)的行為
__ setattr__(self, name, value) 定義當(dāng)一個(gè)屬性被設(shè)置時(shí)的行為
__ delattr__(self, value) 定義當(dāng)一個(gè)屬性被刪除時(shí)的行為
  • 屬性魔法方法初學(xué)者容易犯死循環(huán)如何避免江掩?
    第一種:用super()來調(diào)用基類学辱,比如:super().__ setattr__(name, value)
    第二種:給特殊屬性__ dict__賦值,比如:self.__ dict__[name] = value

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末环形,一起剝皮案震驚了整個(gè)濱河市策泣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抬吟,老刑警劉巖萨咕,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異火本,居然都是意外死亡危队,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門钙畔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茫陆,“玉大人,你說我怎么就攤上這事刃鳄≈殉冢” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長挪鹏。 經(jīng)常有香客問我见秽,道長,這世上最難降的妖魔是什么讨盒? 我笑而不...
    開封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任解取,我火速辦了婚禮,結(jié)果婚禮上返顺,老公的妹妹穿的比我還像新娘禀苦。我一直安慰自己,他們只是感情好遂鹊,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開白布振乏。 她就那樣靜靜地躺著,像睡著了一般秉扑。 火紅的嫁衣襯著肌膚如雪慧邮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天舟陆,我揣著相機(jī)與錄音误澳,去河邊找鬼。 笑死秦躯,一個(gè)胖子當(dāng)著我的面吹牛忆谓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播踱承,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼倡缠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了茎活?” 一聲冷哼從身側(cè)響起毡琉,我...
    開封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妙色,沒想到半個(gè)月后桅滋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡身辨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年丐谋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片煌珊。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡号俐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出定庵,到底是詐尸還是另有隱情吏饿,我是刑警寧澤踪危,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站猪落,受9級(jí)特大地震影響贞远,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜笨忌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一蓝仲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧官疲,春花似錦袱结、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至维费,卻和暖如春棚饵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掩完。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留硼砰,地道東北人且蓬。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像题翰,于是被迫代替她去往敵國和親恶阴。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

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

  • 1豹障、什么叫魔法方法冯事? 魔法方法:Python解釋器自動(dòng)給出默認(rèn)的,是可以給你的類增加魔力的特殊方法血公。如果你的對象實(shí)...
    Bling_ll閱讀 1,054評(píng)論 0 2
  • 一昵仅、快捷鍵 ctr+b 執(zhí)行ctr+/ 單行注釋ctr+c ...
    o_8319閱讀 5,830評(píng)論 2 16
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)累魔。 注意:講述HT...
    kismetajun閱讀 27,522評(píng)論 1 45
  • 久違的艷陽惠臨 凝眸天邊 最唯美的斑斕里 一身華光 履在肩膀 忘情于天藍(lán) 陡然間忘了 秋已待謝含霜 轉(zhuǎn)瞬又將 步入...
    遠(yuǎn)行的安靜閱讀 277評(píng)論 0 1
  • 羅琳的故事 權(quán)威的《福布斯》雜志公布了一份全世界70位身價(jià)億萬級(jí)母親的名單垦写,身價(jià)已達(dá)5.45億英鎊的羅琳赫然在列吕世。...
    康夢橋閱讀 97評(píng)論 0 0