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 相关文章推荐
在IIS服务器上以CGI方式运行Python脚本的教程
Apr 25 Python
Python编程判断这天是这一年第几天的方法示例
Apr 18 Python
Python使用matplotlib绘图无法显示中文问题的解决方法
Mar 14 Python
python 美化输出信息的实例
Oct 15 Python
使用python根据端口号关闭进程的方法
Nov 06 Python
使用python将图片按标签分入不同文件夹的方法
Dec 08 Python
使用Python批量修改文件名的代码实例
Jan 24 Python
基于Tensorflow批量数据的输入实现方式
Feb 05 Python
详解Python中string模块除去Str还剩下什么
Nov 30 Python
Ubuntu20.04环境安装tensorflow2的方法步骤
Jan 29 Python
解决hive中导入text文件遇到的坑
Apr 07 Python
如何理解及使用Python闭包
Jun 01 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
使用array mutisort 实现按某字段对数据排序
2013/06/18 PHP
推荐5款跨平台的PHP编辑器
2014/12/25 PHP
php实现通用的信用卡验证类
2015/03/24 PHP
PHP经典面试题之设计模式(经常遇到)
2015/10/15 PHP
Laravel中如何增加自定义全局函数详解
2017/05/09 PHP
关于URL中的特殊符号使用介绍
2011/11/03 Javascript
js实现的切换面板实例代码
2013/06/17 Javascript
Javascript优化技巧之短路表达式详细介绍
2015/03/27 Javascript
jquery实现的美女拼图游戏实例
2015/05/04 Javascript
可以浮动某个物体的jquery控件用法实例
2015/07/24 Javascript
jquery实现多条件筛选特效代码分享
2015/08/28 Javascript
js获取图片宽高的方法
2015/11/25 Javascript
JavaScript实现简单的tab选项卡切换
2016/01/05 Javascript
javascript中的后退和刷新实现方法
2016/11/10 Javascript
DOM 事件的深入浅出(一)
2016/12/05 Javascript
详解vue-cli中的ESlint配置文件eslintrc.js
2017/09/25 Javascript
ES6学习教程之对象字面量详解
2017/10/09 Javascript
vue学习之mintui picker选择器实现省市二级联动示例
2017/10/12 Javascript
利用vue.js实现被选中状态的改变方法
2018/02/08 Javascript
JavaScript一元正号运算符示例代码
2019/06/30 Javascript
vue学习笔记之Vue中css动画原理简单示例
2020/02/29 Javascript
Vue-cli assets SubDirectory及PublicPath区别详解
2020/08/18 Javascript
使用IronPython把Python脚本集成到.NET程序中的教程
2015/03/31 Python
Python在Windows和在Linux下调用动态链接库的教程
2015/08/18 Python
python 去除二维数组/二维列表中的重复行方法
2019/01/23 Python
Python.append()与Python.expand()用法详解
2019/12/18 Python
keras小技巧——获取某一个网络层的输出方式
2020/05/23 Python
python复合条件下的字典排序
2020/12/18 Python
群众路线教育实践活动学习笔记内容
2014/11/06 职场文书
故意伤害人身损害赔偿协议书
2014/11/19 职场文书
优秀高中学生评语
2014/12/30 职场文书
清洁员岗位职责
2015/02/15 职场文书
自主招生自荐信范文
2015/03/04 职场文书
期中考试后的感想
2015/08/07 职场文书
MySQL命令行操作时的编码问题详解
2021/04/14 MySQL
go goth封装第三方认证库示例详解
2022/08/14 Golang