# python对象获取属性值时会去查找以下两个魔法函数是否被重写
# __getattr__, __getattribute__
# __getattr__ 在查找不到属性的时候调用
# __getattribute__ 无条件调用该函数
from datetime import date
class User:
def __init__(self, info):
self.info = info
# 属性不存在时调用
def __getattr__(self, item):
return self.info.get(item)
# 不管属性是否存在,都会调用,所以不建议重写
# def __getattribute__(self, item):
# return "running"
if __name__ == '__main__':
user = User({"name": "Lone", "birthday": date(2000, 1, 1)})
# 访问不存在的属性(name、birthday、nothing)报错
# AttributeError: 'User' object has no attribute 'age'
# 重写__getattr__获取info中对应key的value,没有对应key返回None
print(user.info)
print(user.name)
print(user.birthday)
print(user.nothing)
属性描述符和属性的查找过程
属性描述符
class IntField:
def __get__(self, instance, owner):
pass
def __set__(self, instance, value):
pass
def __delete__(self, instance):
pass
实现上述三个魔法函数其中之一即可成为属性描述符,
如果只实现__get__称之为非数据属性描述符,
只有同时实现__get__和__set__才称之为数据属性描述符
属性查找过程
如果user是某个类的实例,那么user.age(以及等价的getattr(user, “age”)),首先调用__getattribute__,如果类定义了__getattr__方法,那么在__getattribute__抛出AttributeError的时候就会调用__getattr__,
而对于描述符(get)的调用,则发生在__getattribute__内部
user = User()
user.age
顺序如下:
- 如果“age”是出现在User或其基类的__dict__中,并且age是data descriptor(数据属性描述符),那么调用其__get__方法,否则
- 如果“age”出现在user(对象)的__dict__中,那么直接返回user._dict_[age],否则
- 如果“age”出现在User或其基类的__dict__中
3.1 如果age是non-data descriptor(非数据属性描述符),那么调用其__get__方法,否则
3.2 返回__dict__[age] - 如果User有__getattr__方法,调用__getattr__方法,否则
- 抛出AttributeError