python的描述符(descriptor)、装饰器(property)造成的一个无限递归问题分享


Posted in Python onJuly 09, 2014

分享一下刚遇到的一个小问题,我有一段类似于这样的python代码:

# coding: utf-8
class A(object):
    @property

    def _value(self):

#        raise AttributeError("test")

        return {"v": "This is a test."}
    def __getattr__(self, key):

        print "__getattr__:", key

        return self._value[key]
if __name__ == '__main__':

    a = A()

    print a.v

运行后可以得到正确的结果
__getattr__: v

This is a test.

但是注意,如果把
#        raise AttributeError("test")

这行的注释去掉的话,即在_value方法里面抛出AttributeError异常,事情就会变得有些奇怪。程序运行的时候并不会抛出异常,而是会进入一个无限递归:

File "attr_test.py", line 12, in __getattr__

    return self._value[key]

  File "attr_test.py", line 12, in __getattr__

    return self._value[key]

RuntimeError: maximum recursion depth exceeded while calling a Python object

通过多方查找后发现是property装饰器的问题,property实际上是一个descriptor。在python doc中可以发现这样的文字:

object.__get__(self, instance, owner)
Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner. This method should return the (computed) attribute value or raise an AttributeError exception.

这样当用户访问._value时,抛出了AttributeError从而调用了__getattr__方法去尝试获取。这样程序就变成了无限递归。

这个问题看上去不复杂,但是当你的_value方法是比较隐晦的抛出AttributeError的话,调试起来就会比较困难了。

Python 相关文章推荐
python的else子句使用指南
Feb 27 Python
Linux下通过python访问MySQL、Oracle、SQL Server数据库的方法
Apr 23 Python
Python实现约瑟夫环问题的方法
May 03 Python
详解Python核心编程中的浅拷贝与深拷贝
Jan 07 Python
python3爬取淘宝信息代码分析
Feb 10 Python
python分治法求二维数组局部峰值方法
Apr 03 Python
python中返回矩阵的行列方法
Apr 04 Python
使用Python获取网段IP个数以及地址清单的方法
Nov 01 Python
Python填充任意颜色,不同算法时间差异分析说明
May 16 Python
详解pyinstaller生成exe的闪退问题解决方案
Jun 19 Python
Python reversed反转序列并生成可迭代对象
Oct 22 Python
python文件名批量重命名脚本实例代码
Apr 22 Python
Python中__init__和__new__的区别详解
Jul 09 #Python
Python中使用logging模块代替print(logging简明指南)
Jul 09 #Python
Python中的魔法方法深入理解
Jul 09 #Python
gearman的安装启动及python API使用实例
Jul 08 #Python
python实现跨文件全局变量的方法
Jul 07 #Python
Python中的并发编程实例
Jul 07 #Python
Python编程语言的35个与众不同之处(语言特征和使用技巧)
Jul 07 #Python
You might like
全国FM电台频率大全 - 31 新疆维吾尔族自治区
2020/03/11 无线电
一个颜色轮换的简单例子
2006/10/09 PHP
PHP下escape解码函数的实现方法
2010/08/08 PHP
PHP静态文件生成类实例
2014/11/29 PHP
深入理解PHP的远程多会话调试
2017/09/21 PHP
PHP设计模式之状态模式定义与用法详解
2018/04/02 PHP
laravel框架上传图片实现实时预览功能
2019/10/14 PHP
JS IE和FF兼容性问题汇总
2009/02/09 Javascript
JavaScript计算字符串中每个字符出现次数的小例子
2013/07/02 Javascript
一款由jquery实现的整屏切换特效
2014/09/15 Javascript
Bootstrap布局组件应用实例讲解
2016/02/17 Javascript
jquery利用json实现页面之间传值的实例解析
2016/12/12 Javascript
基于Javascript实现的不重复ID的生成器
2016/12/25 Javascript
详解Vue.js 2.0 如何使用axios
2017/04/21 Javascript
JavaScrpt中如何使用 cookie 设置查看与删除功能
2017/07/09 Javascript
详解vue-cli脚手架中webpack配置方法
2018/08/22 Javascript
详解一个小实例理解js原型和继承
2019/04/24 Javascript
javascript开发实现贪吃蛇游戏
2020/07/31 Javascript
[03:17]2014DOTA2 国际邀请赛中国区预选赛 四强专访
2014/05/23 DOTA
[00:35]DOTA2上海特级锦标赛 EG战队宣传片
2016/03/04 DOTA
详解Django框架中用户的登录和退出的实现
2015/07/23 Python
Python中字符串的修改及传参详解
2016/11/30 Python
使用tensorflow实现线性回归
2018/09/08 Python
python 实现手机自动拨打电话的方法(通话压力测试)
2019/08/08 Python
基于python实现简单网页服务器代码实例
2020/09/14 Python
python 制作简单的音乐播放器
2020/11/25 Python
pycharm 快速解决python代码冲突的问题
2021/01/15 Python
HTML5使用DOM进行自定义控制示例代码
2013/06/08 HTML / CSS
十佳教师事迹材料
2014/01/11 职场文书
致跳远运动员广播稿
2014/02/11 职场文书
技能比赛获奖感言
2014/02/14 职场文书
人力资源管理求职信
2014/08/07 职场文书
五年级学生评语大全
2014/12/26 职场文书
宾馆客房管理制度
2015/08/06 职场文书
Spring整合Mybatis的全过程
2021/06/28 Java/Android
SpringBoot整合RabbitMQ的5种模式实战
2021/08/02 Java/Android