__getattr__ 和 __getattribute__ 区别

这两个是类对象的魔法函数,在访问对象属性的时候会被调用

 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__方法,获取默认值;否则会直接抛错。

原文地址:https://www.cnblogs.com/Deaseyy/p/13676317.html