1.__getattr__(self,name)
定义当用户试图获取一个不存在的属性时的行为
2.__getattribute__(self,name)
定义当该类的属性被访问时的行为
3.__setattr__(self,name,value)
定义当一个属性被设置时的行为
4.__delattr__(self,name)
定义当一个属性被删除时的行为
以上方法皆可以重写
>>> class C:
def __getattribute__(self,name):
print('getattribute')
return super().__getattribute__(name) '''此处写return是因为getattribute方法需要一个返回值'''
def __getattr__(self,name):
print('getattr') '''此处没有调用父类是因为getattr只有在属性不存在时被调用,在这里调用会出错'''
def __setattr__(self,name,value):
print('setattr')
super().__setattr__(name,value)
def __delattr__(self,name):
print('delattr')
super().__delattr__(name)
>>> c = C()
>>> c.x '''此处试图访问c.x,调用getattibute,但是并不存在,所以又调用getattr'''
getattribute
getattr
>>> c.x = 1 '''此处直接给c.x赋值,所以直接调用setattr'''
setattr
>>> del c.x '''此处删除了c.x,所以调用了delattr'''
delattr
注意以下代码!
class Rectangle:
def __init__(self,width=0,height=0):
self.width = width
self.height = height
def __setattr__(self,name,value):
if name == 'square':
self.width = value
self.height = value
else:
self.name = value
'''此句会触发递归,因为当试图给一个属性width或height赋值时,
便会调用setattr,又调用回来了,所以会触发递归。'''
'''可以用以下两句中的任意一句进行修改!'''
super().__setattr__(name,value) #此句是通过父类的setattr进行赋值,不会出现再调用回来的递归错误
self.__dict__[name] = value #此句是通过dict索引来改变name对应的属性的值(赋值)
def getArea(self):
return self.width * self.height
请指出以下代码的问题
初学者重写属性魔法方法很容易陷入的一个误区就是木有“观前顾后”。
class Counter:
def __init__(self):
self.counter = 0 # 这里会触发 __setattr__ 调用
def __setattr__(self, name, value):
self.counter += 1
“““既然需要 __setattr__ 调用后才能真正设置 self.counter 的值,所以这时候 self.counter 还没有定义,所以没法 += 1,错误的根源。”””
super().__setattr__(name, value)
def __delattr__(self, name):
self.counter -= 1
super().__delattr__(name)
修改后:
>>> class Counter:
k = []
def __init__(self):
self.counter = 0
def __setattr__(self,name,value):
if name != 'counter':
if name not in self.k:
self.counter += 1
self.k.append(name)
super().__setattr__(name,value)
def __delattr__(self,name):
self.counter -=1
self.k.remove(name)
super().__delattr__(name)
>>> c = Counter()
>>> c.x = 1
>>> c.counter
1
>>> c.y = 2
>>> c.counter
2
>>> del c.x
>>> c.counter
1