Python魔法方法之__getattr__和getattribute
这两种魔法方法在Python中很容易混淆:__getattr__和getattribute。通常我们会定义__getattr__而且从来不定义getattribute,下面我们来看看这两者的区别。

__getattr__魔法方法
classMyClass:
def__init__(self,x):
self.x=x
def__getattr__(self,item):
print('{}属性为找到!'.format(item))
returnNone
>>>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.来到对象的继承链寻找,如果找不到执行第四步
4.调用obj.__getattr__方法,如果用户没有定义或仍然找不到,抛出Attributeerror异常,属性搜索失败!
classMyClass: def__init__(self,x): self.x=x >>>obj=MyClass(1) >>>obj.y AttributeError:'MyClass'objecthasnoattribute'a'
以上代码未定义___getattr__魔法方法,如果找不到属性,就会抛出异常。
相关推荐:Python视频教程
__getattribute__魔法方法
当我们调用对象的属性时,我们将首先调用__getattribute__魔法方法。
obj.x obj.__getattribute__(x)
以上代码,这两个代码实际上是等价的。当__getattribute__如果发现失败,会调用__getattr__方法。
代码演示
classMyClass:
def__init__(self,x):
self.x=x
def__getattribute__(self,item):
print('属性{}'正在获取;.format(item))
returnsuper(MyClass,self).__getattribute__(item)
>>>obj=MyClass(2)
>>>obj.x
属性x正在获取
2使用_____getattribute__魔法方法时,回到父亲的方法,否则很难写对。下面的代码是一个陷阱,会产生递归。
classMyClass:
def__init__(self,x):
self.x=x
def__getattribute__(self,item):
print('属性{}'正在获取;.format(item))
returnself.item
>>>obj=MyClass(2)
>>>obj.x
File"xxx",line11,in__getattribute__
print('属性{}'正在获取;.format(item))
RecursionError:maximumrecursiondepthexceededwhilecallingaPythonobject上面的代码似乎是对的,但它们被调入递归陷阱,相当于
def__getattribute__(self,item):
print('属性{}'正在获取;.format(item))
returnself.__getattribute__(item)非常警惕。
此外,内置的getattr和hasatr也会触发这种魔法方法。
>>>getattr(obj,'x',None) 属性x正在获取 2 >>>hasattr(obj,'x',None) 属性x正在获取 True
需要注意其他细节
classMyClass:
x=999
def__init__(self,x):
self.x=x
def__getattribute__(self,item):
print('属性{}'正在获取;.format(item))
returnsuper(MyClass,self).__getattribute__(item)在上述代码中,定义了类属性x和实例属性x,这两个属性是同名的。根据Python语法规则,当对象获得属性x时,它将首先在实例属性中找到,如果找不到,则返回类属性。
>>>obj=MyClass(2) >>>print(obj.x) 属性x正在获取 2 >>>delobj.x#删除实例属性x >>>print(obj.x)#此时访问的是类属性 正在获得属性 999
这样就可以证实上面提到的__getattribute__搜索顺序。通常这种方法可以在框架中使用,一般不需要使用。
