__getattr__
:每当访问类对象的属性,此时实例字典又找不到该属性时,触发__getattr__,简言之:访问实例化对象没有的属性时触发
__getattribute__
:主要访问对象中的属性就会触发此方法
__setattr__
:只要给对象进行属性赋值操作就会触发此方法,无论是直接赋值还是通过setattr函数赋值
这里有个技巧需要知道,如果想要访问属性或者设置属性赋值的过程不触发
__ ** __
方法,可以使用super().__getattr__('name')
、super().__getattribute__('name')
、super().__setattr__('key', 'value')
来处理。
示例:
class DictionaryRecord:
def __init__(self, data):
self._data = data
self.a = 1
def __getattribute__(self, item):
print(f"call __getattribute__({item !r})")
data_dict = super().__getattribute__('_data') # 超类的__getattribute__方法是直接从实例的属性字典获取的,不会触发__getattritube__
return data_dict[item]
def __setattr__(self, key, value):
print(f"__setattr__ is run...")
print(key, value)
super().__setattr__(key, value)
data = DictionaryRecord({'foo': 3})
print(data.foo)
Result:
setattr is run...
_data {'foo': 3}
setattr is run...
a 1
call getattribute('foo')
3
Tips:
"Harold's a clever {0!s}" # Calls str() on the argument first "Bring out the holy {name!r}" # Calls repr() on the argument first "More {!a}" # Calls ascii() on the argument first
要点总结
1、如果想要用自己的方式(例如惰性地或按需地)加载并保存对象属性,那么可以在该对象所属的类里实现__getattr__
与__setattr__
特殊方法
2、__getattr__
只会在属性缺失时触发,而__getattribute__
则在每次访问属性时都要触发
3、在实现__getattribute__
与__setattr__
的过程中,如果要使用本对象的普通属性,那么应该通过super()(也就是object类)来使用,而不要直接使用,以避免无限递归