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中的面向对象编程的概念
Apr 27 Python
一篇文章入门Python生态系统(Python新手入门指导)
Dec 11 Python
浅析Python基础-流程控制
Mar 18 Python
python3中bytes和string之间的互相转换
Feb 09 Python
Python3之文件读写操作的实例讲解
Jan 23 Python
python按行读取文件,去掉每行的换行符\n的实例
Apr 19 Python
对python中类的继承与方法重写介绍
Jan 20 Python
Python OpenCV实现视频分帧
Jun 01 Python
Python反爬虫伪装浏览器进行爬虫
Feb 28 Python
Spring http服务远程调用实现过程解析
Jun 11 Python
python+appium+yaml移动端自动化测试框架实现详解
Nov 24 Python
Python实现GIF动图以及视频卡通化详解
Dec 06 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
PHP中3种生成XML文件方法的速度效率比较
2012/10/06 PHP
Codeigniter通过SimpleXML将xml转换成对象的方法
2015/03/19 PHP
php正则去除网页中所有的html,js,css,注释的实现方法
2016/11/03 PHP
JQuery实现自定义对话框的代码
2008/06/15 Javascript
谈谈关于JavaScript 中的 MVC 模式
2013/04/11 Javascript
jQuery bxCarousel实现图片滚动切换效果示例代码
2013/05/15 Javascript
jQuery提交多个表单的小技巧
2014/07/27 Javascript
JS中自定义定时器让它在某一时刻执行
2014/09/02 Javascript
JavaScript中使用Object.create()创建对象介绍
2014/12/30 Javascript
jQuery中:password选择器用法实例
2015/01/03 Javascript
ECMAScript 5严格模式(Strict Mode)介绍
2015/03/02 Javascript
详解JavaScript的Polymer框架中的通知交互
2015/07/29 Javascript
基于js实现checkbox批量选中操作
2016/11/22 Javascript
使用jQuery的ajax方法向服务器发出get和post请求的方法
2017/01/13 Javascript
bootstrap Validator 模态框、jsp、表单验证 Ajax提交功能
2017/02/17 Javascript
详解通过JSON数据使用VUE.JS
2017/05/26 Javascript
Javasript设计模式之链式调用详解
2018/04/26 Javascript
微信小程序实现自动定位功能
2018/10/31 Javascript
JS为什么说async/await是generator的语法糖详解
2019/07/11 Javascript
使用react context 实现vue插槽slot功能
2019/07/18 Javascript
RxJS在TypeScript中的简单使用详解
2020/04/13 Javascript
[57:59]完美世界DOTA2联赛循环赛 Ink Ice vs LBZS BO2第一场 11.05
2020/11/05 DOTA
python操作MongoDB基础知识
2013/11/01 Python
Python标准库之随机数 (math包、random包)介绍
2014/11/25 Python
Python实现八大排序算法
2016/08/13 Python
解决python中os.listdir()函数读取文件夹下文件的乱序和排序问题
2018/10/17 Python
Python中那些 Pythonic的写法详解
2019/07/02 Python
Python中实现输入超时及如何通过变量获取变量名
2020/01/18 Python
Python变量作用域LEGB用法解析
2020/02/04 Python
解决python便携版无法直接运行py文件的问题
2020/09/01 Python
YesBabyOnline美国:全球性的在线婚纱礼服工厂
2018/05/05 全球购物
社区助残日活动总结
2014/08/29 职场文书
2015年五一劳动节慰问信
2015/03/23 职场文书
国庆阅兵观后感
2015/06/15 职场文书
2015年科普工作总结
2015/07/23 职场文书
把77A收信机改造成收音机
2022/04/05 无线电