在__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] |
未定义属性attr,进行点号运算-实例名.attr时,自动调用__getattr__()方法,所以可以在方法体对已定义属性进行点号运算,不会产生循环,因为实例名.已定义属性,不会触发__getattr__()方法。注意,方法体内不能对未定义属性进行点号运算,否则会产生循环。
描述
getattr方法体内,未定义属性attr,self.attr,点号运算触发无限循环。
示例
>>> class LoopGet:
a=1
def __init__(self):
self.b=2
def __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,点号运算,触发循环
描述
__getattr__拦截未定义属性的点号运算,方法体内,self.已定义属性,拦截已定义属性来避免循环,或者直接return其他值来避免循环。
示例
>>> class LoopGet:
a=1
def __init__(self):
self.b=2
def __getattr__(self,attr):
print('获取属性值',attr)
# 已定义属性attr,self.attr,点号运算,不调用 __getattr__ , 避免循环
x=self.a
>>> lg=LoopGet()
>>> lg.c
获取属性值 c
未定义属性、已定义属性attr,进行点号运算-实例名.attr时,都会自动调用__getattribute__()方法,所以在方法体通过self.属性,对其他属性进行点号运算时,会触发__getattribute__(),导致产生循环。通过object.__getattribute__()避免无限循环。
描述
getattribute方法体内,self.属性名,自动调用当前实例的getattribute,导致无限循环。
示例
>>> class LoopGet:
a=1
def __init__(self):
self.b=2
def __getattribute__(self,attr):
print('获取属性值',attr)
# 已定义属性attr,self.attr,点号运算,触发循环
x=self.b
>>> lg=LoopGet()
>>> lg.a
获取属性值 a
获取属性值 b
获取属性值 b
获取属性值 b
#无限循环获取属性 b
>>> class LoopGet:
a=1
def __init__(self):
self.b=2
def __getattribute__(self,attr):
print('获取属性值',attr)
# 未定义属性attr,self.attr,点号运算,触发循环
x=self.attr
>>> lg=LoopGet()
>>> lg.a
获取属性值 a
获取属性值 attr
获取属性值 attr
获取属性值 attr
#无限循环获取属性 attr
描述
getattribute方法体内,self.__dict__,自动调用当前实例的getattribute,导致无限循环。
示例
>>> class LoopGet:
a=1
def __init__(self):
self.b=2
def __getattribute__(self,attr):
print('获取属性值',attr)
# self.__dict__ 触发 __getattribute__ ,导致循环
x=self.__dict__[attr]
>>> lg=LoopGet()
>>> lg.a
获取属性值 a
获取属性值 __dict__
获取属性值 __dict__
描述
getattribute方法体内,object.__getattribute__(self,attr),自动调用超类object的getattribute,避免无限循环。
示例
>>> class LoopGet:
a=1
def __init__(self):
self.b=2
def __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.c
File "<pyshell#16>", line 8, in __getattribute__
return object.__getattribute__(self,attr)
AttributeError: 'LoopGet' object has no attribute 'c'
未定义属性或已定义类属性或已定义实例属性为attr,实例名.attr=value,自动调用python的__setattr__()方法。在setattr方法体内,self.attr=value,自动调用当前实例的setattr,导致无限循环。通过self.__dict__[attr]=value、object.__setattr__(self,attr,value)来避免无限循环。
__delattr__()和__setattr__()使用相同的方法来避免循环。
描述
setattr方法体内,self.attr=value,自动调用当前实例的setattr,导致无限循环。
示例
>>> class LoopGet:
a=1
def __init__(self):
self.b=2
def __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
描述
__setattr__()方法体内,self.__dict__[attr]=value,不调用setattr,避免循环。
示例
>>> class LoopGet:
a=1
def __init__(self):
self.b=2
def __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
描述
__setattr__()方法体内,object.__setattr__(self,attr,value),自动调用超类object的setattr,避免无限循环。
示例
>>> class LoopGet:
a=1
def __init__(self):
self.b=2
def __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
del 实例名.attr,自动调用python的__delattr__()方法。在setattr方法体内,del self.attr自动调用当前实例的delattr,导致无限循环。
通过del self.__dict__[attr]、object.__delattr__(self,attr)来避免无限循环。
注:只能删实例属性,不能删类属性。
描述
__delattr__()方法体内,del self.attr,自动调用当前实例的delattr,导致无限循环。
示例
>>> class LoopDel:
a=1
def __init__(self):
self.b=2
def __delattr__(self,attr):
print('删除属性',attr)
# del self.attr ,调用当前实例的 delattr , 导致循环
del self.attr
>>> ld=LoopDel()
>>> del ld.a
删除属性 a
删除属性 attr
删除属性 attr
删除属性 attr
删除属性 attr
描述
__delattr__()方法体内,del self.__dict__[attr],不调用delattr,避免循环。
注:只能删实例属性,不能删类属性。
示例
>>> class LoopDel:
a=1
def __init__(self):
self.b=2
def __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.a
File "<pyshell#60>", line 9, in __delattr__
del self.__dict__[attr]
KeyError: 'a'
描述
__delattr__()方法体内,object.__delattr__(self,attr),自动调用超类object的delattr,避免无限循环。
注:只能删实例属性,不能删类属性。
示例
>>> class LoopDel:
a=1
def __init__(self):
self.b=2
def __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.a
File "<pyshell#66>", line 8, in __delattr__
object.__delattr__(self,attr)
AttributeError: a