1 python属性管理getattr、getattribute、setattr和delattr避免循环
在__getattr__()、__getattribute__()和__setattr__()方法体内,通过self进行对应的点号运算、赋值运算,会自动调用当前实例的相应方法,导致无限循环。通过object或者__dict__可以避免循环。
NO | 项目 | 方法体内避免循环 |
---|---|---|
1 | __getattr__() | 已定义属性attr,self.attr |
2 | __getattribute__() | object.__getattribuite__(self,attr) |
3 | __setattr__() | object.__setattr__(self,attr,value) self.__dict__[attr]=value |
4 | __delattr__() | object.__delattr__(self,attr) del self.__dict__[attr] |
1.1 getattr
未定义属性attr,进行点号运算-实例名.attr时,自动调用__getattr__()方法,所以可以在方法体对已定义属性进行点号运算,不会产生循环,因为实例名.已定义属性,不会触发__getattr__()方法。注意,方法体内不能对未定义属性进行点号运算,否则会产生循环。
1.1.1 self.attr触发无限循环
描述
getattr方法体内,未定义属性attr,self.attr,点号运算触发无限循环。
示例
>>> class LoopGet:a=1def __init__(self):self.b=2def __getattr__(self,attr):print('获取属性值',attr)# 未定义属性attr,self.attr,点号运算,触发循环x=self.attr>>> lg=LoopGet()
>>> lg.a
1
>>> lg.c
获取属性值 c
获取属性值 attr
获取属性值 attr
获取属性值 attr
获取属性值 attr
# 未定义属性attr,实例名.attr,点号运算,触发循环
1.1.2 访问已定义属性避免循环
描述
__getattr__拦截未定义属性的点号运算,方法体内,self.已定义属性,拦截已定义属性来避免循环,或者直接return其他值来避免循环。
示例
>>> class LoopGet:a=1def __init__(self):self.b=2def __getattr__(self,attr):print('获取属性值',attr)# 已定义属性attr,self.attr,点号运算,不调用 __getattr__ , 避免循环x=self.a>>> lg=LoopGet()
>>> lg.c
获取属性值 c
1.2 getattribute
未定义属性、已定义属性attr,进行点号运算-实例名.attr时,都会自动调用__getattribute__()方法,所以在方法体通过self.属性,对其他属性进行点号运算时,会触发__getattribute__(),导致产生循环。通过object.__getattribute__()避免无限循环。
1.2.1 self.attr触发无限循环
描述
getattribute方法体内,self.属性名,自动调用当前实例的getattribute,导致无限循环。
示例
>>> class LoopGet:a=1def __init__(self):self.b=2def __getattribute__(self,attr):print('获取属性值',attr)# 已定义属性attr,self.attr,点号运算,触发循环x=self.b
>>> lg=LoopGet()
>>> lg.a
获取属性值 a
获取属性值 b
获取属性值 b
获取属性值 b
#无限循环获取属性 b>>> class LoopGet:a=1def __init__(self):self.b=2def __getattribute__(self,attr):print('获取属性值',attr)# 未定义属性attr,self.attr,点号运算,触发循环x=self.attr>>> lg=LoopGet()
>>> lg.a
获取属性值 a
获取属性值 attr
获取属性值 attr
获取属性值 attr
#无限循环获取属性 attr
1.2.2 self.__dict__触发无限循环
描述
getattribute方法体内,self.__dict__,自动调用当前实例的getattribute,导致无限循环。
示例
>>> class LoopGet:a=1def __init__(self):self.b=2def __getattribute__(self,attr):print('获取属性值',attr)# self.__dict__ 触发 __getattribute__ ,导致循环x=self.__dict__[attr]>>> lg=LoopGet()
>>> lg.a
获取属性值 a
获取属性值 __dict__
获取属性值 __dict__
1.2.3 object.getattribute()避免循环
描述
getattribute方法体内,object.__getattribute__(self,attr),自动调用超类object的getattribute,避免无限循环。
示例
>>> class LoopGet:a=1def __init__(self):self.b=2def __getattribute__(self,attr):print('获取属性值',attr)# object全部类的超类,通过 object.__getattribute__ 避免循环return object.__getattribute__(self,attr)>>> lg=LoopGet()
>>> lg.a
获取属性值 a
1
>>> lg.c
获取属性值 c
Traceback (most recent call last):File "<pyshell#19>", line 1, in <module>lg.cFile "<pyshell#16>", line 8, in __getattribute__return object.__getattribute__(self,attr)
AttributeError: 'LoopGet' object has no attribute 'c'
1.3 setattr
未定义属性或已定义类属性或已定义实例属性为attr,实例名.attr=value,自动调用python的__setattr__()方法。在setattr方法体内,self.attr=value,自动调用当前实例的setattr,导致无限循环。通过self.__dict__[attr]=value、object.__setattr__(self,attr,value)来避免无限循环。
__delattr__()和__setattr__()使用相同的方法来避免循环。
1.3.1 self.attr=value触发无限循环
描述
setattr方法体内,self.attr=value,自动调用当前实例的setattr,导致无限循环。
示例
>>> class LoopGet:a=1def __init__(self):self.b=2def __setattr__(self,attr,value):print('设置属性值',attr)# self.attr 触发 __getattribute__ ,导致循环self.attr=value# 构造函数的 self.b=2 调用 setattr,方法体内 self.attr=value ,触发无限循环
>>> lg=LoopGet()
设置属性值 b
设置属性值 attr
设置属性值 attr
设置属性值 attr
1.3.2 self.dict[attr]=value避免循环
描述
__setattr__()方法体内,self.__dict__[attr]=value,不调用setattr,避免循环。
示例
>>> class LoopGet:a=1def __init__(self):self.b=2def __setattr__(self,attr,value):print('设置属性值',attr)# self.__dict__[attr]=value 不调用 __getattribute__ ,避免循环self.__dict__[attr]=value>>> lg=LoopGet()
设置属性值 b
>>> lg.a=11
设置属性值 a
>>> lg.b=3
设置属性值 b
>>> lg.c=5
设置属性值 c
>>> lg.c
5
1.3.3 object.setattr(self,attr,value)避免循环
描述
__setattr__()方法体内,object.__setattr__(self,attr,value),自动调用超类object的setattr,避免无限循环。
示例
>>> class LoopGet:a=1def __init__(self):self.b=2def __setattr__(self,attr,value):print('设置属性值',attr)# object.__setattr__(self,attr,value) 调用超类setattr ,避免循环object.__setattr__(self,attr,value)>>> lg=LoopGet()
设置属性值 b
>>> lg.a=11
设置属性值 a
>>> lg.b=3
设置属性值 b
>>> lg.c=5
设置属性值 c
>>> lg.c
5
1.4 delattr
del 实例名.attr,自动调用python的__delattr__()方法。在setattr方法体内,del self.attr自动调用当前实例的delattr,导致无限循环。
通过del self.__dict__[attr]、object.__delattr__(self,attr)来避免无限循环。
注:只能删实例属性,不能删类属性。
1.4.1 del self.attr触发无限循环
描述
__delattr__()方法体内,del self.attr,自动调用当前实例的delattr,导致无限循环。
示例
>>> class LoopDel:a=1def __init__(self):self.b=2def __delattr__(self,attr):print('删除属性',attr)# del self.attr ,调用当前实例的 delattr , 导致循环del self.attr>>> ld=LoopDel()
>>> del ld.a
删除属性 a
删除属性 attr
删除属性 attr
删除属性 attr
删除属性 attr
1.4.2 del self.dict[attr]避免循环
描述
__delattr__()方法体内,del self.__dict__[attr],不调用delattr,避免循环。
注:只能删实例属性,不能删类属性。
示例
>>> class LoopDel:a=1def __init__(self):self.b=2def __delattr__(self,attr):print('删除属性',attr)# del self.__dict__[attr] ,不调用 delattr , 避免循环# 只能删 实例属性, 不能删类属性del self.__dict__[attr]>>> ld=LoopDel()
# 删实例属性
>>> del ld.b
删除属性 b
# 删类属性失败
>>> del ld.a
删除属性 a
Traceback (most recent call last):File "<pyshell#64>", line 1, in <module>del ld.aFile "<pyshell#60>", line 9, in __delattr__del self.__dict__[attr]
KeyError: 'a'
1.4.3 object.__delattr(self,attr)避免循环
描述
__delattr__()方法体内,object.__delattr__(self,attr),自动调用超类object的delattr,避免无限循环。
注:只能删实例属性,不能删类属性。
示例
>>> class LoopDel:a=1def __init__(self):self.b=2def __delattr__(self,attr):print('删除属性',attr)# object.__delattr__(self,attr) ,调用超类 delattr , 避免循环# 只能删 实例属性, 不能删类属性object.__delattr__(self,attr)>>> ld=LoopDel()
>>> del ld.b
删除属性 b
>>> del ld.a
删除属性 a
Traceback (most recent call last):File "<pyshell#69>", line 1, in <module>del ld.aFile "<pyshell#66>", line 8, in __delattr__object.__delattr__(self,attr)
AttributeError: a