知行编程网知行编程网  2022-10-11 11:00 知行编程网 隐藏边栏  13 
文章评分 0 次,平均分 0.0
导语: 本文主要介绍了关于Python魔法方法之__getattr__和getattribute的相关知识,包括python getchar,以及getrequesturi这些编程知识,希望对大家有参考作用。

Python 中有两种神奇的方法可能会让人困惑:__getattr__ 和 getattribute。通常我们定义__getattr__,从不定义getattribute,我们来看看两者的区别。

Python魔术方法__getattr__和getattribute


__getattr__魔法方法

class MyClass:
    def __init__(self, x):
        self.x = x
    def __getattr__(self, item):
        print('{}属性为找到!'.format(item))
        return None
>>> obj = MyClass(1)
>>> obj.x
1
>>> obj.y
y属性为找到!
None

我们定义一个MyClass类,设置一个实例属性为x,值为1。obj是这个类的一个实例,获取obj.x返回1,获取obj.y发现找不到该属性,因为实例变量obj的不包含y,当找不到属性时会调用__getattr__方法。

**调用__getattr__详细过程如下:**

obj.attr

1、首先会在对象的实例属性中搜索,第二步找不到。

2.到对象所在的类中找到类属性,如果找不到,进入第3步

3.来到对象的继承链中查找,如果找不到,进行第4步

4. 调用 obj.__getattr__ 方法。如果用户没有定义或者还是找不到,就会抛出AttributeError异常,属性搜索失败!

class MyClass:
    def __init__(self, x):
        self.x = x
>>> obj = MyClass(1)
>>> obj.y
AttributeError: 'MyClass' object has no attribute 'a'

如上面的代码,如果没有定义__getattr__魔法方法,并且找不到该属性,就会抛出异常。


__getattribute__魔法方法

当我们调用对象的属性时,首先调用 __getattribute__ 魔术方法。

obj.x
obj.__getattribute__(x)

上面的代码,这两个代码其实是等价的。当 __getattribute__ 查找失败时,会调用 __getattr__ 方法。

代码演示

class MyClass:
    def __init__(self, x):
        self.x = x
    def __getattribute__(self, item):
        print('正在获取属性{}'.format(item))
        return super(MyClass, self).__getattribute__(item)
>>> obj = MyClass(2)
>>> obj.x
正在获取属性x
2

我们在使用__getattribute__魔术方法的时候,需要返回父类的方法,否则很难写正确。下面的代码是一个陷阱,会引起递归。

class MyClass:
    def __init__(self, x):
        self.x = x
    def __getattribute__(self, item):
        print('正在获取属性{}'.format(item))
        return self.item
        
>>> obj = MyClass(2)
>>> obj.x
  File "xxx", line 11, in __getattribute__
    print('正在获取属性{}'.format(item))
RecursionError: maximum recursion depth exceeded while calling a Python object

上面的代码看起来是正确的,但是它调用了递归陷阱,相当于

def __getattribute__(self, item):
    print('正在获取属性{}'.format(item))
    return self.__getattribute__(item)

要十分警惕。

另外,内置的getattr和hasattr也会触发这个魔法方法。

>>> getattr(obj, 'x', None)
正在获取属性x
2
>>> hasattr(obj, 'x', None)
正在获取属性x
True


其他细节需要注意

class MyClass:
    x = 999
    
    def __init__(self, x):
        self.x = x
    def __getattribute__(self, item):
        print('正在获取属性{}'.format(item))
        return super(MyClass, self).__getattribute__(item)

在上面的代码中,定义了一个类属性 x 和一个实例属性 x。这两个属性具有相同的名称。根据Python语法规则,当对象获取到属性x时,会先寻找实例属性,如果没有找到,会回到类的属性中查找。

>>> obj = MyClass(2)
>>> print(obj.x)
正在获取属性x
2
>>> del obj.x  #删除了实例属性x
>>> print(obj.x)  #此时访问的是类属性
正在获取属性
999

这证实了上面提到的 __getattribute__ 的搜索顺序。通常这种方法可以在框架中使用,一般不需要使用。

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

知行编程网
知行编程网 关注:1    粉丝:1
这个人很懒,什么都没写
扫一扫二维码分享