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实现查询IP地址所在地
Mar 29 Python
Python中SOAP项目的介绍及其在web开发中的应用
Apr 14 Python
Windows下的Python 3.6.1的下载与安装图文详解(适合32位和64位)
Feb 21 Python
Python实现利用163邮箱远程关电脑脚本
Feb 22 Python
修复 Django migration 时遇到的问题解决
Jun 14 Python
Python实现在某个数组中查找一个值的算法示例
Jun 27 Python
为什么Python中没有"a++"这种写法
Nov 27 Python
Django中在xadmin中集成DjangoUeditor过程详解
Jul 24 Python
Python Django 命名空间模式的实现
Aug 09 Python
Python变量作用域LEGB用法解析
Feb 04 Python
解决python对齐错误的方法
Jul 16 Python
Pycharm无法打开双击没反应的问题及解决方案
Aug 17 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获取ip对应地区和使用网络类型的方法
2015/03/11 PHP
thinkphp微信开发(消息加密解密)
2015/12/02 PHP
简单的pgsql pdo php操作类实现代码
2016/08/25 PHP
PHP+Ajax实现的无刷新分页功能详解【附demo源码下载】
2017/07/03 PHP
PHP的mysqli_stat()函数讲解
2019/01/23 PHP
JavaScript 判断判断某个对象是Object还是一个Array
2010/01/28 Javascript
js验证整数加保留小数点的简单实例
2013/12/02 Javascript
javascript教程:关于if简写语句优化的方法
2014/05/17 Javascript
JS获取当前日期时间并定时刷新示例
2021/03/04 Javascript
网页中表单按回车就自动提交的问题的解决方案
2014/11/03 Javascript
AngularJs Injecting Services Into Controllers详解
2016/09/02 Javascript
NodeJs安装npm包一直失败的解决方法
2017/04/28 NodeJs
AngualrJs清除定时器遇到的坑
2017/10/13 Javascript
详解Vue2 SSR 缓存 Api 数据
2017/11/20 Javascript
解决Vue不能检测数组或对象变动的问题
2018/02/24 Javascript
Node.js 的 GC 机制详解
2019/06/03 Javascript
LayUI switch 开关监听 获取属性值、更改状态的方法
2019/09/21 Javascript
jQuery实现移动端下拉展现新的内容回弹动画
2020/06/24 jQuery
Javascript新手入门之字符串拼接与变量的应用
2020/12/03 Javascript
[58:15]2018DOTA2亚洲邀请赛 4.1 小组赛 A组 NB vs Liquid
2018/04/02 DOTA
Python FTP操作类代码分享
2014/05/13 Python
Python中DJANGO简单测试实例
2015/05/11 Python
python脚本设置超时机制系统时间的方法
2016/02/21 Python
老生常谈python的私有公有属性(必看篇)
2017/06/09 Python
python format 格式化输出方法
2018/07/16 Python
python求质数的3种方法
2018/09/28 Python
python 实现turtle画图并导出图片格式的文件
2019/12/07 Python
英国排名第一的礼品体验公司:Red Letter Days
2018/08/16 全球购物
是否可以从一个static方法内部发出对非static方法的调用?
2014/08/18 面试题
注塑工厂厂长岗位职责
2013/12/02 职场文书
运动会100米解说词
2014/01/23 职场文书
学校消防安全制度
2014/01/30 职场文书
奥林匹克的口号
2014/06/13 职场文书
暑期培训心得体会
2014/09/02 职场文书
2014年幼儿园学期工作总结
2014/12/05 职场文书
基于Redis位图实现用户签到功能
2021/05/08 Redis