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 相关文章推荐
wxPython事件驱动实例详解
Sep 28 Python
Python lxml模块安装教程
Jun 02 Python
python中requests和https使用简单示例
Jan 18 Python
django用户注册、登录、注销和用户扩展的示例
Mar 19 Python
Windows下Anaconda2安装NLTK教程
Sep 19 Python
Python过滤txt文件内重复内容的方法
Oct 21 Python
Python File(文件) 方法整理
Feb 18 Python
python中metaclass原理与用法详解
Jun 25 Python
python plotly绘制直方图实例详解
Jul 22 Python
Python实现性能自动化测试竟然如此简单
Jul 30 Python
python GUI库图形界面开发之PyQt5树形结构控件QTreeWidget详细使用方法与实例
Mar 02 Python
Python连续赋值需要注意的一些问题
Jun 03 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
咖啡语言
2021/03/03 咖啡文化
apache+mysql+php+ssl服务器之完全安装攻略
2006/09/05 PHP
PHP swfupload图片上传的实例代码
2013/09/30 PHP
PHP+ajax实现上传、删除、修改单张图片及后台处理逻辑操作详解
2020/02/12 PHP
PHP笛卡尔积实现原理及代码实例
2020/12/09 PHP
javascript 对象的定义方法
2007/01/10 Javascript
基于Jquery的回车成tab焦点切换效果代码(Enter To Tab )
2010/11/14 Javascript
js 获取(接收)地址栏参数值的方法
2013/04/01 Javascript
js获得页面的高度和宽度的方法
2014/02/23 Javascript
Iframe实现跨浏览器自适应高度解决方法
2014/09/02 Javascript
JavaScript数组常用操作技巧汇总
2014/11/17 Javascript
JS组件Form表单验证神器BootstrapValidator
2016/01/26 Javascript
Bootstrap前端开发案例一
2016/06/17 Javascript
Javascript基础学习笔记(菜鸟必看篇)
2016/07/22 Javascript
video.js使用改变ui过程
2017/03/05 Javascript
详解Angular.js数据绑定时自动转义html标签及内容
2017/03/30 Javascript
详解有关easyUI的拖动操作中droppable,draggable用法例子
2017/06/03 Javascript
ionic3+Angular4实现接口请求及本地json文件读取示例
2017/10/11 Javascript
javascript的this关键字详解
2019/05/20 Javascript
JavaScript箭头函数中的this详解
2019/06/19 Javascript
《javascript设计模式》学习笔记三:Javascript面向对象程序设计单例模式原理与实现方法分析
2020/04/07 Javascript
vue项目打包之开发环境和部署环境的实现
2020/04/23 Javascript
Vue+penlayers实现多边形绘制及展示
2020/12/24 Vue.js
python中正则表达式 re.findall 用法
2018/10/23 Python
使用Python合成图片的实现代码(图片添加个性化文本,图片上叠加其他图片)
2020/04/30 Python
使用gunicorn部署django项目的问题
2020/12/30 Python
10分钟理解CSS3 FlexBox弹性布局
2018/12/20 HTML / CSS
The North Face北面美国官网:美国著名户外品牌
2018/09/15 全球购物
LVMH旗下最大的奢侈品网站平台:24S
2020/05/24 全球购物
PHP数据运算类型都有哪些
2013/11/05 面试题
企业管理毕业生求职信
2014/03/11 职场文书
地球一小时活动总结
2015/02/27 职场文书
2015最新学生自我评价范文
2015/03/03 职场文书
十二生肖观后感
2015/06/12 职场文书
警用民用对讲机找不同
2022/02/18 无线电
MySQL学习之基础操作总结
2022/03/19 MySQL