前言
object 类里面有个 __getattribute__
方法,作用是类实例化调用属性和方法的时候都会调用一次,返回该类的属性。
如果调用的属性没有,会抛出 AttributeError 异常。如果属性查找(attribute lookup)在实例以及对应的类中(通过__dict__
)失败, 那么会调用到类的__getattr__
方法。
__getattribute__方法
A类在调用自身属性的时候,是不会触发__getattribute__方法。
只有在调用A()实例属性或方法的时候,才会触发__getattribute__方法
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
class A(object):
count = 0
def __init__(self):
self.name = "yoyo"
self.age = 18
def start(self):
print("start1111111")
def __getattribute__(self, item):
"""属性拦截器"""
print("调用了A类的属性:", item)
return object.__getattribute__(self, item)
a = A()
# A()实例对象属性会调用__getattribute__
print(a.count)
print(a.age)
print(a.name)
print(a.start())
如果A类属性(__dict__
)没查找到,并且实例属性和方法也没找到,此时会抛出 AttributeError 异常
a = A()
print(a.weight) # 找不到属性
运行结果
调用了A类的属性: weight
Traceback (most recent call last):
File "demo/aaa.py", line 27, in <module>
print(a.weight) # 找不到属性
File "demo/aaa.py", line 18, in __getattribute__
return object.__getattribute__(self, item)
AttributeError: 'A' object has no attribute 'weight'
__getattr__方法
如果属性查找(attribute lookup)在实例以及对应的类中(通过__dict__
)失败, 那么会调用到类的__getattr__
方法。
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
class A(object):
count = 0
def __init__(self):
self.name = "yoyo"
self.age = 18
def start(self):
print("start1111111")
def __getattribute__(self, item):
"""属性拦截器"""
print("调用了A类的属性:", item)
return object.__getattribute__(self, item)
def __getattr__(self, item):
"""属性找不到会执行这个方法"""
print("找不到该属性:%s" % item)
return 'not found'
a = A()
# A()实例对象属性会调用__getattribute__
print(a.count)
print(a.age)
print(a.weight)
运行结果不会出现异常
调用了A类的属性: count
0
调用了A类的属性: age
18
调用了A类的属性: weight
找不到该属性:weight
not found
使用场景
网上有个很经典的使用示例,访问字典的key,像访问属性一样访问字典。
字典取值有2种方式,通过dict[key] 和dict.get(key)的方式取值。
a = {
"name": "yoyo",
"age": 18
}
# 字典访问
print(a["name"])
print(a.get("name"))
在其它语言里面,比如javascript里面可以把json当一个object对象,通过a.name,a.age这种点的方式就能直接取值了。
于是我们自己写一个类来实现这种方式
class ObjectDict(dict):
def __init__(self, *args, **kwargs):
super(ObjectDict, self).__init__(*args, **kwargs)
def __getattr__(self, name):
value = self[name]
if isinstance(value, dict):
value = ObjectDict(value)
return value
if __name__ == '__main__':
a = {
"name": "yoyo",
"age": 18
}
obj = ObjectDict(a)
print(obj.name)
print(obj.age)
也可以传多个值
if __name__ == '__main__':
obj = ObjectDict(a={'age': 1, 'name': 'yoyo'}, d=True)
print(obj.a)
print(obj.a.name)
print(obj.d)
dict嵌套dict也可以通过.的方式取值
if __name__ == '__main__':
obj = ObjectDict(a={'age': 1,
'name': 'yoyo',
'data': {'id': 11, 'tel': 12345678900}}, d=True)
print(obj.a)
print(obj.a.name)
print(obj.a.data)
print(obj.a.data.id)
print(obj.a.data.tel)
运行结果
{'age': 1, 'name': 'yoyo', 'data': {'id': 11, 'tel': 12345678900}}
yoyo
{'id': 11, 'tel': 12345678900}
11
12345678900