今天介绍以下四个访问属性的魔法方法:
__getattribute__(self, item):
__getattr__(self, item):
__setattr__(self, key, value):
__delattr__(self, item):
先定义一个类用来做实验:
class C:
def __getattribute__(self, item):
print('getattribute')
return super().__getattribute__(item) #默认继承object类
def __getattr__(self, item):
print('getattr')
def __setattr__(self, key, value):
print('setattr')
super().__setattr__(key,value)
def __delattr__(self, item):
print('delattr')
super().__delattr__(item)
1. 若访问一个不存在的属性时:
c1=C()
print(c1.x)
获取不存在属性的时候:getattribute比getattr先调用
先通过getattribute查找属性→找不到属性的时候采用getattr
↓
2. 若访问一个存在的属性时:
c1.x=1
print(c1.x)
获取存在属性的时候:仅调用getattribute方法
↓
3. 删除一个属性:
del c1.x
4. 用一个例子引入:死循环陷阱 → 矩形类:
#死循环陷阱 -- 矩形类例子
class Rectangle():
def __init__(self, w=0, h=0):
self.width=w
self.height=h
def __setattr__(self, name, value):
if name=='square':
self.width=value
self.height=value
else:
self.name=value #无限递归__setattr__,会错误 无限次调用本类的赋值方法
def getArea(self):
return self.width*self.height
r1=Rectangle(4,5)
print(r1.getArea())
r1.square=10
print(r1.getArea())
print(r1.__dict__)
r1.width=5 #尝试只改变width属性
print(r1.getArea())
print(r1.__dict__)
错误原因:无限递归本类的_ _ setattr _ _,会错误 无限次调用本类的赋值方法;
↓
解决办法1:调用基类方法(※推荐)
class Rectangle():
def __init__(self, w=0, h=0):
self.width=w
self.height=h
def __setattr__(self, name, value):
if name=='square':
self.width=value
self.height=value
else:
super().__setattr__(name,value) #推荐:方法一:调用基类方法
def getArea(self):
return self.width*self.height
r1=Rectangle(4,5)
print(r1.getArea())
r1.square=10
print(r1.getArea())
print(r1.__dict__)
r1.width=5 #尝试只改变width属性
print(r1.getArea())
print(r1.__dict__)
↓
解决办法2:利用字典改变
class Rectangle():
def __init__(self, w=0, h=0):
self.width=w
self.height=h
def __setattr__(self, name, value):
if name=='square':
self.width=value
self.height=value
else:
self.__dict__[name] = value #方法二:利用字典改变
def getArea(self):
return self.width*self.height
r1=Rectangle(4,5)
print(r1.getArea())
r1.square=10
print(r1.getArea())
print(r1.__dict__)
r1.width=5 #尝试只改变width属性
print(r1.getArea())
print(r1.__dict__)
补充:property:
class C:
def __init__(self,size=10):
self.size=size
def getSize(self):
return self.size
def setSize(self,value):
self.size=value
def deleteSize(self):
del self.size
x=property(getSize,setSize,deleteSize)
1. 赋值操作:
c1.x=100
2. 访问操作:
print(c1.x)
3. 删除操作:
del c1.x