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 当前全局变量和入口参数的所有属性
Jul 01 Python
解析Mac OS下部署Pyhton的Django框架项目的过程
May 03 Python
Python实现二分查找与bisect模块详解
Jan 13 Python
django使用html模板减少代码代码解析
Dec 12 Python
Python基于csv模块实现读取与写入csv数据的方法
Jan 18 Python
Python3之简单搭建自带服务器的实例讲解
Jun 04 Python
Python通过TensorFlow卷积神经网络实现猫狗识别
Mar 14 Python
详解有关PyCharm安装库失败的问题的解决方法
Feb 02 Python
通过python检测字符串的字母
Feb 18 Python
PyQt5实现登录页面
May 30 Python
Python使用jpype模块调用jar包过程解析
Jul 29 Python
PyQt5通过信号实现MVC的示例
Feb 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执行速度全攻略(上)
2006/10/09 PHP
按上下级层次关系输出内容的PHP代码
2010/07/17 PHP
解析php中的fopen()函数用打开文件模式说明
2013/06/20 PHP
jquery 弹出层实现代码
2009/10/30 Javascript
jQuery ready函数滥用分析
2011/02/16 Javascript
详谈jQuery Ajax(load,post,get,ajax)的用法
2017/03/02 Javascript
微信小程序中顶部导航栏的实现代码
2017/03/30 Javascript
jQuery取得元素标签名称小结(附代码)
2017/08/16 jQuery
在vue中利用全局路由钩子给url统一添加公共参数的例子
2019/11/01 Javascript
JavaScript中CreateTextFile函数
2020/08/30 Javascript
[04:03]DOTA2英雄梦之声_第02期_风暴之灵
2014/06/30 DOTA
Python使用百度API上传文件到百度网盘代码分享
2014/11/08 Python
简洁的十分钟Python入门教程
2015/04/03 Python
Python合并多个装饰器小技巧
2015/04/28 Python
Python设计实现的计算器功能完整实例
2017/08/18 Python
对python opencv 添加文字 cv2.putText 的各参数介绍
2018/12/05 Python
python绘制散点图并标记序号的方法
2018/12/11 Python
Python 获取项目根路径的代码
2019/09/27 Python
python判断无向图环是否存在的示例
2019/11/22 Python
在Keras中利用np.random.shuffle()打乱数据集实例
2020/06/15 Python
Pandas中两个dataframe的交集和差集的示例代码
2020/12/13 Python
英国灯具和灯泡网上商店:Lights.co.uk
2018/02/02 全球购物
三星印度官网:Samsung印度
2019/08/03 全球购物
捷克家具销售网站:SCONTO Nábytek
2020/01/02 全球购物
颇特女士香港官网:NET-A-PORTER香港
2021/03/08 全球购物
小区门卫工作职责
2013/12/14 职场文书
大学生志愿者感言
2014/01/15 职场文书
机电专业大学生职业规划书范文
2014/02/25 职场文书
股权转让意向书
2014/04/01 职场文书
给校长的建议书300字
2014/05/16 职场文书
中学生民族团结演讲稿
2014/08/27 职场文书
大学教师个人总结
2015/02/10 职场文书
离婚代理词范文
2015/05/23 职场文书
2016年世界艾滋病日宣传活动总结
2016/04/01 职场文书
解决Go gorm踩过的坑
2021/04/30 Golang
公历12个月名称的由来
2022/04/12 杂记