內(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