在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

  1. 首先会在对象的实例属性中寻找,找不到执行第二步
  2. 来到对象所在的类中查找类属性,如果还找不到执行第三步
  3. 来到对象的继承链上寻找,如果还找不到执行第四步
  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__的查找顺序。通常该方法在框架中可能会用到,一般情况下无需使用。

Python魔法方法__getattr__和__getattribute__详解的更多相关文章

  1. python魔法方法:__getattr__,__setattr__,__getattribute__

    python魔法方法:__getattr__,__setattr__,__getattribute__ 难得有时间看看书....静下心来好好的看了看Python..其实他真的没有自己最开始想的那么简单 ...

  2. python 魔法方法补充(__setattr__,__getattr__,__getattribute__)

    python 魔法方法补充 1 getattribute (print(ob.name) -- obj.func())当访问对象的属性或者是方法的时候触发 class F(object): def _ ...

  3. python魔法方法大全

    1.python魔法方法详解: python魔法方法是可以修改重载的,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而 ...

  4. with上下文管理 python魔法方法

    with语法在Python里很常见, 主要的利好是使用代码更简洁. 常见的使用场景有: 1. 资源对象的获取与释放. 使用with可以简化try...finally ... 2. 在不修改函数代码的前 ...

  5. python设计模式之迭代器与生成器详解(五)

    前言 迭代器是设计模式中的一种行为模式,它提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示.python提倡使用生成器,生成器也是迭代器的一种. 系列文章 python设计模 ...

  6. 1. Python 魔法方法

    Python 魔法方法 基础: 如果你想... 所以,你写... Python调用... 初始化一个实例 x = MyClass() x.__init__() 作为一个字符串的"官方&quo ...

  7. Python魔法方法总结及注意事项

    1.何为魔法方法: Python中,一定要区分开函数和方法的含义: 1.函数:类外部定义的,跟类没有直接关系的:形式: def func(*argv): 2.方法:class内部定义的函数(对象的方法 ...

  8. python 3.x 爬虫基础---Urllib详解

    python 3.x 爬虫基础 python 3.x 爬虫基础---http headers详解 python 3.x 爬虫基础---Urllib详解 前言 爬虫也了解了一段时间了希望在半个月的时间内 ...

  9. python selenium 三种等待方式详解[转]

    python selenium 三种等待方式详解   引言: 当你觉得你的定位没有问题,但是却直接报了元素不可见,那你就可以考虑是不是因为程序运行太快或者页面加载太慢造成了元素不可见,那就必须要加等待 ...

随机推荐

  1. 在项目中使用CLR规划

    1.创建自己的项目 2.对"解..."→参加→目→C#→数据库→SQL Server项目,例如以下图所看到的: 3.选择操作数据库 4.创建存储过程 5.代码(详见:CLR存储过程 ...

  2. Web报表进度条显示

    创建插件 <script src="../CreateControl.js" type="text/javascript"></script& ...

  3. Android 平台下Ftp 使用模拟器需要注意的问题

    以下代码在pc上测试通过,可是在android模拟器上就不工作,不过还可以链接到服务器但不能得到文件 纠结了半天,原来是模式的问题,具体请Google 模拟器中采用建议被动模式 public void ...

  4. Android中SQLite数据库操作(2)——SQLiteOpenHelper类

    如果开发者对SQL语法不熟悉,我要告诉你一个好消息,Android提供了一个SQLiteOpenHelper类. 在实际项目中很少使用SQLiteDatabase的方法(请看:http://blog. ...

  5. 让你编写的控件库在 XAML 中有一个统一的漂亮的命名空间(xmlns)和命名空间前缀

    原文 让你编写的控件库在 XAML 中有一个统一的漂亮的命名空间(xmlns)和命名空间前缀 在 WPF XAML 中使用自己定义的控件时,想必大家都能在 XAML 中编写出这个控件的命名空间了.然而 ...

  6. Leetcode 94 Binary Tree Inorder Traversal 二叉树

    二叉树的中序遍历,即左子树,根, 右子树 /** * Definition for binary tree * struct TreeNode { * int val; * TreeNode *lef ...

  7. WPF中3D旋转的实现

    原文:WPF中3D旋转的实现 关于3D旋转的原理,请看Daniel Lehenbauer的文章 <Rotating the Camera with the Mouse> http://vi ...

  8. WPF获取读取电脑指定文件夹中的指定文件的地址

    //保存指定文件夹中的指定文件的地址 string List<string> mListUri = new List<string>(); //文件夹地址 string fol ...

  9. linux nano 命令

    linux nano一linux像pico文本编辑软件,功能少.但是,基本能满足要求

  10. 精装友好联络算法实现借壳和RI

    精装友好联络会 注册算法分析: 1.  许可证由三部分组成. 2. 的登记号的第一部分是顺序编号0x6d模 3. 登记代码的第二部分: 先将订单号与0XB25F1异或,将异或后的结果转换成十进制字符串 ...