Python魔法方法__getattr__和__getattribute__详解
2019-06-26 17:48
1511 查看
在Python中有这两个魔法方法容易让人混淆:__getattr__和getattribute。通常我们会定义__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
- 首先会在对象的实例属性中寻找,找不到执行第二步
- 来到对象所在的类中查找类属性,如果还找不到执行第三步
- 来到对象的继承链上寻找,如果还找不到执行第四步
- 调用
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__的查找顺序。通常该方法在框架中可能会用到,一般情况下无需使用。
相关文章推荐
- Python学习笔记 魔法方法之__getattr__、__getattribute__解析
- python魔法方法:__getattr__,__setattr__,__getattribute__
- Python魔法方法之属性访问 ( __getattr__, __getattribute__, __setattr__, __delattr__ )
- python魔法方法:__getattr__,__setattr__,__getattribute__
- 详解Python中 __get__和__getattr__和__getattribute__的区别
- python魔法方法-自定义序列详解
- python魔法方法-属性转换和类的表示详解
- Python的hasattr() getattr() setattr() 函数使用方法详解
- 【Python】4胖学Python - __getattr__() 和 __getattribute__() 方法的区别
- 详解Python中 __get__和__getattr__和__getattribute__的区别
- Python的hasattr() getattr() setattr() 函数使用方法详解
- python中的几个理论性的问题详解(装饰器运行步骤,@staticmethod和@classmethod区别,单例模式,魔法方法,object继承与不继承区别)
- Python的hasattr() getattr() setattr() 函数使用方法详解
- Python的hasattr() getattr() setattr() 函数使用方法详解--转载
- Python的hasattr() getattr() setattr() 函数使用方法详解
- Python的hasattr() getattr() setattr() 函数使用方法详解
- python 中__setattr__, __getattr__,__getattribute__, __call__使用方法
- Python的hasattr() getattr() setattr() 函数使用方法详解
- Python 魔法方法详解
- [zz]Python - __getattr__() 和 __getattribute__() 方法的区别