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 修改文件指定行的方法
May 15 Python
python多线程http下载实现示例
Dec 30 Python
python网络编程学习笔记(10):webpy框架
Jun 09 Python
跟老齐学Python之大话题小函数(2)
Oct 10 Python
用Python编写一个简单的Lisp解释器的教程
Apr 03 Python
简单介绍Python2.x版本中的cmp()方法的使用
May 20 Python
Python中json格式数据的编码与解码方法详解
Jul 01 Python
python+tkinter编写电脑桌面放大镜程序实例代码
Jan 16 Python
Python3实现的爬虫爬取数据并存入mysql数据库操作示例
Jun 06 Python
python装饰器常见使用方法分析
Jun 26 Python
Django视图类型总结
Feb 17 Python
python爬取豆瓣电影排行榜(requests)的示例代码
Feb 18 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获取当前时间的毫秒数的方法
2014/01/26 PHP
php用ini_get获取php.ini里变量值的方法
2015/03/04 PHP
workerman结合laravel开发在线聊天应用的示例代码
2018/10/30 PHP
动态刷新 dorado树的js代码
2009/06/12 Javascript
浅谈Javascript事件处理程序的几种方式
2012/06/27 Javascript
实现点击列表弹出列表索引的两种方式
2013/03/08 Javascript
Javascript中查找不以XX字符结尾的单词示例代码
2013/10/15 Javascript
Js+Jq获取URL参数的集中方法示例代码
2014/05/20 Javascript
PHP+jQuery+Ajax实现多图片上传效果
2015/03/14 Javascript
js实现图片无缝滚动特效
2020/03/19 Javascript
Bootstrap源码解读按钮(5)
2016/12/23 Javascript
JS解决position:sticky的兼容性问题的方法
2017/10/17 Javascript
JS+WCF实现进度条实时监测数据加载量的方法详解
2017/12/19 Javascript
基于js中的存储键值对以及注意事项介绍
2018/03/30 Javascript
axios全局注册,设置token,以及全局设置url请求网段的方法
2018/09/25 Javascript
小程序如何获取多个formId实现详解
2019/09/20 Javascript
Vue使用自定义指令实现拖拽行为实例分析
2020/06/06 Javascript
Vue项目打包编译优化方案
2020/09/16 Javascript
[01:42:49]DOTA2-DPC中国联赛 正赛 iG vs PSG.LGD BO3 第一场 2月26日
2021/03/11 DOTA
使用PDB模式调试Python程序介绍
2015/04/05 Python
python urllib爬取百度云连接的实例代码
2017/06/19 Python
Python探索之URL Dispatcher实例详解
2017/10/28 Python
pycharm下打开、执行并调试scrapy爬虫程序的方法
2017/11/29 Python
Flask框架信号用法实例分析
2018/07/24 Python
python创造虚拟环境方法总结
2019/03/04 Python
Python 20行简单实现有道在线翻译的详解
2019/05/15 Python
Pytorch 中retain_graph的用法详解
2020/01/07 Python
使用tkinter实现三子棋游戏
2021/02/25 Python
CSS3 函数技巧 用css 实现js实现的事情(clac Counters Tooltip)
2017/08/15 HTML / CSS
迪斯尼商品官方网站:ShopDisney
2016/08/01 全球购物
ParcelABC西班牙:包裹运送和快递服务
2019/12/24 全球购物
介绍一下.NET构架下remoting和webservice
2014/05/08 面试题
瀑布模型都有哪些优缺点
2014/06/23 面试题
股东协议书
2014/04/14 职场文书
幼儿园教师个人总结
2015/02/05 职场文书
python小型的音频操作库mp3Play
2022/04/24 Python