这两个是类对象的魔法函数,在访问对象属性的时候会被调用
1 class A(object): 2 def __init__(self, x): 3 self.x = x 4 5 def __getattr__(self, item): 6 print('run __getattr__') 7 return 100 8 9 def __getattribute__(self, item): 10 print('run __getattribute__') 11 return super(A, self).__getattribute__(item) 12 13 a = A(10) 14 print(a.x) 15 print(a.y)
结果:
# a.x
>> 执行 __getattribute__ >> 10 # a.y
>> 执行 __getattribute__ >> 执行 __getattr__ >> 100
从结果可以看出,获取对象属性时:
无论属性是否存在,都会先调用__getattribute__ 方法;
在调用__getattribute__ 方法获取不到属性时,才会去调用__getattr__方法;
所以我们可在__getattr__方法中返回属性不存在时的默认值。
拿drf源码中的一个实际例子来说:
class Request(object): @property def content_type(self): meta = self._request.META return meta.get(CONTENT_TYPE', meta.get('HTTP_CONTENT_TYPE', ''))
@property def query_params(self): return self._request.GET def __getattr__(self, attr): try: return getattr(self._request, attr) except AttributeError: return self.__getattribute__(attr)
DRF中的request 对django原生的request对象做了二次封装,Request类中也实现了一些方法用于获取原生request中的一些属性,但是实现的方法有限,这些方法并不能取到原生request的所有属性;所以使用__getattr__来操作,在当前request对象取不到指定属性时,就会执行__getattr__方法,去_request(原生request)中取该属性。
使用getattr获取属性:
使用getattr()
方法获取对象属性时,也是同样的调用关系,只不过只有在getattr()
带第三个参数作为默认值时,才会调用__getattr__
方法,获取默认值;否则会直接抛错。