python的描述符(descriptor)、装饰器(property)造成的一个无限递归问题分享

yipeiwu_com6年前Python基础

分享一下刚遇到的一个小问题,我有一段类似于这样的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的加密模块md5、sha、crypt使用实例

MD5(Message-Digest Algorithm 5) 模块用于计算信息密文(信息摘要),得出一个128位的密文。sha模块跟md5相似,但生成的是160位的签名。使用方法是相同...

python中reader的next用法

python中有个csv包(build-in),该包有个reader,按行读取csv文件中的数据 reader.next()作用:打印csv文件中的第一行标题header (python...

pandas按若干个列的组合条件筛选数据的方法

pandas按若干个列的组合条件筛选数据的方法

还是用图说话 A文件: 比如,我想筛选出“设计井别”、“投产井别”、“目前井别”三列数据都为11的数据,结果如下: 当然,这里的筛选条件可以根据用户需要自由调整,代码如下: #...

Linux 下 Python 实现按任意键退出的实现方法

某天在群内有同学问到,在python下我用input或者raw_input都得输入完后回车才能获取到输入的值,那如何实现任意键退出暂停等功能呢,我当时也没有多想,因为接触python时间...

python变量的存储原理详解

python变量的存储原理详解

变量的存储 在高级语言中,变量是对内存及其地址的抽象。 对于python而言,python的一切变量都是对象,变量的存储,采用了引用语义的方式,存储的只是一个变量的值所在的内存地址,而...