getattr, __getattr__, __getattribute__和__get__区别

一、getattr()

和另外三个方法都是魔法函数不同的是,getattr()是python内置的一个函数,它可以用来获取对象的属性和方法。例子如下:

class A():
    a = 5
    def __init__(self, x):
        self.x = x

    def hello(self):
        return 'hello func'

a = A(10)

print(getattr(a, 'x'))  #相当于a.x
print(getattr(a, 'y', 20))  #相当于a.y,因为a.y并不存在,所以返回第三个参数作为默认值
print(getattr(a, 'hello')())  # 相当于a.hello()

print(getattr(A, 'a'))  # 相当于A.a

这段代码的输出结果是:

10
20
hello func
5

可以看出,getattr()可以用来获取对像的属性和方法,需要注意的是,如果通过getattr()来尝试获取对象里并不存在的属性时没有添加第三个默认值,代码会 报错,如下所示:

print(getattr(a, 'y'))

运行会报异常提示找不到属于y:

Traceback (most recent call last):
  File "app/test.py", line 32, in 
    print(getattr(a, 'y'))
AttributeError: 'A' object has no attribute 'y'

二、__getattr()与__getattribute()

这两个是类对象的魔法函数,在访问对象属性的时候会被调用,但是两者之间也有一点区别, 我们通过代码来看一下:

class A(object):
  def __init__(self, x):
    self.x = x

  def hello(self):
    return 'hello func'

  def __getattr__(self, item):
    print('in __getattr__')
    return 100

  def __getattribute__(self, item):
    print('in __getattribute__')
    return super(A, self).__getattribute__(item)

a = A(10)
print(a.x)
print(a.y)

运行代码,得到下面输出:

in __getattribute__
10
in __getattribute__
in __getattr__
100

可以看出,在获到对象属性时,__getattribute__()是一定会被调用的,无论属性存不存在,首先都会调用这个魔法方法。 如果调用像a.y这种不存在的对象时,调用__getattribute__()找不到y这个属性,就会再调用__getattr__()这个魔法方法,可以通过在这个方法里实 来设置属性不存在时的默认值。使用上面的getattr()方法获取属性时,也是同样的调用关系,只不过只有在getattr()带第三个参数作为默认值时,才会调用 __getattr__()方法。

三、__get__()

__get__() 是一个描述符协议(Descriptor Protocol)中的魔法函数,用于定义描述符对象的获取行为。描述符是一种特殊的对象,用于控制对属性的访问。描述符可以被用作类的属性,通过访问和设置描述符属性,可以触发 __get__()__set__() 和 __delete__() 等方法。

在描述符协议中,当通过实例访问描述符属性时,解释器会自动调用描述符对象的 __get__() 方法,并传入三个参数:

  • self: 描述符对象自身的实例。
  • instance: 调用描述符的实例对象。
  • owner: 描述符所属的类对象。

__get__() 方法的返回值将作为属性的值返回给调用方。

下面是一个简单的示例,演示了如何使用 __get__() 方法定义一个描述符:

class Descriptor:
    def __get__(self, instance, owner):
        print("Getting the value")
        return instance._value

    def __set__(self, instance, value):
        print("Setting the value")
        instance._value = value

class MyClass:
    descriptor = Descriptor()

    def __init__(self, value):
        self._value = value

my_obj = MyClass(42)
print(my_obj.descriptor)  # 输出: Getting the value, 42
my_obj.descriptor = 100   # 输出: Setting the value
print(my_obj.descriptor)  # 输出: Getting the value, 100

 getattr, __getattr__, __getattribute__和__get__区别_第1张图片

在上述示例中,Descriptor 类是一个描述符,它定义了 __get__() 和 __set__() 方法。MyClass 类中的 descriptor 属性是一个描述符实例。当通过 my_obj.descriptor 访问该属性时,会触发 Descriptor 类中的 __get__() 方法,并返回 _value 属性的值。当给 my_obj.descriptor 赋值时,会触发 Descriptor 类中的 __set__() 方法,将新的值赋给 _value 属性。

需要注意的是,描述符协议还包括 __set__() 和 __delete__() 方法,用于定义设置和删除描述符属性的行为。这些方法可以根据需要进行实现,以控制描述符属性的行为。

 

参考:

getattr, __getattr__, __getattribute__和__get__区别 - 知乎

你可能感兴趣的:(python,python,开发语言)