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中的日志模块logging
Jun 19 Python
python制作企业邮箱的爆破脚本
Oct 05 Python
浅析python中SQLAlchemy排序的一个坑
Feb 24 Python
python读写json文件的简单实现
Apr 11 Python
django静态文件加载的方法
May 20 Python
wxpython多线程防假死与线程间传递消息实例详解
Dec 13 Python
在Python中利用pickle保存变量的实例
Dec 30 Python
Python拼接字符串的7种方式详解
Mar 19 Python
详解基于Jupyter notebooks采用sklearn库实现多元回归方程编程
Mar 25 Python
python实现简单遗传算法
Sep 18 Python
解决使用Pandas 读取超过65536行的Excel文件问题
Nov 10 Python
Python绘制散点图之可视化神器pyecharts
Jul 07 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 咖啡文化
PHP session常见问题集锦及解决办法总结
2007/03/18 PHP
解析CI即CodeIgniter框架在Nginx下的重写规则
2013/06/03 PHP
使用phpQuery采集网页的方法
2013/11/13 PHP
PHP中使用GD库创建圆形饼图的例子
2014/11/19 PHP
PHP编写简单的App接口
2016/08/28 PHP
thinkphp5 URL和路由的功能详解与实例
2017/12/26 PHP
PHP排序二叉树基本功能实现方法示例
2018/05/26 PHP
javascript基础第一章 JavaScript与用户端
2010/07/22 Javascript
javascript时间自动刷新实现原理与步骤
2013/01/06 Javascript
jquery中邮箱地址 URL网站地址正则验证实例代码
2013/09/15 Javascript
JavaScript控制两个列表框listbox左右交换数据的方法
2015/03/18 Javascript
jQuery实现立体式数字滚动条增加效果
2016/12/21 Javascript
详谈js使用in和hasOwnProperty获取对象属性的区别
2017/04/25 Javascript
vue实现弹框遮罩点击其他区域弹框关闭及v-if与v-show的区别介绍
2018/09/29 Javascript
JavaScript创建对象的四种常用模式实例分析
2019/01/11 Javascript
在vue-cli 3中给stylus、sass样式传入共享的全局变量
2019/08/12 Javascript
JS严格模式原理与用法实例分析
2020/04/27 Javascript
原生javascript如何实现共享onload事件
2020/07/03 Javascript
[46:59]完美世界DOTA2联赛PWL S2 GXR vs Ink 第二场 11.19
2020/11/20 DOTA
解析Python中的二进制位运算符
2015/05/13 Python
Python实现的网页截图功能【PyQt4与selenium组件】
2018/07/12 Python
基于随机梯度下降的矩阵分解推荐算法(python)
2018/08/31 Python
python获取服务器响应cookie的实例
2018/12/28 Python
Python如何使用函数做字典的值
2019/11/30 Python
Python面向对象程序设计之私有变量,私有方法原理与用法分析
2020/03/23 Python
Python如何转换字符串大小写
2020/06/04 Python
Python中logging日志记录到文件及自动分割的操作代码
2020/08/05 Python
加拿大建筑和装修专家:Reno-Depot
2017/12/21 全球购物
俄罗斯大型在线书店:Читай-город
2019/10/10 全球购物
技术总监的工作职责
2013/11/13 职场文书
高中军训广播稿
2014/01/14 职场文书
机关干部四风问题自查报告及整改措施
2014/10/26 职场文书
2015年端午节活动策划书
2015/05/05 职场文书
卢旺达饭店观后感
2015/06/05 职场文书
Nginx如何配置多个服务域名解析共用80端口详解
2022/09/23 Servers