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 pillow模块使用方法详解

pillow Pillow是PIL的一个派生分支,但如今已经发展成为比PIL本身更具活力的图像处理库。pillow可以说已经取代了PIL,将其封装成python的库(pip即可安装),...

python单例模式的多种实现方法

前言 单例模式(Singleton Pattern),是一种软件设计模式,是类只能实例化一个对象, 目的是便于外界的访问,节约系统资源,如果希望系统中 只有一个对象可以访问,就用单例模式...

python回调函数的使用方法

有两种类型的回调函数:复制代码 代码如下:blocking callbacks (also known as synchronous callbacks or just callback...

Python实现九宫格式的朋友圈功能内附“马云”朋友圈

Python实现九宫格式的朋友圈功能内附“马云”朋友圈

PIL(Python Imaging Library)是一个非常强大的Python库,但是它支持Python2.X, 在Python3中则使用的是Pillow库,它是从PIL中fork出...

Python opencv实现人眼/人脸识别以及实时打码处理

Python opencv实现人眼/人脸识别以及实时打码处理

利用Python+opencv实现从摄像头捕获图像,识别其中的人眼/人脸,并打上马赛克。 系统环境:Windows 7 + Python 3.6.3 + opencv 3.4.2 一、系...