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

yipeiwu_com5年前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 Tkinter模块实现时钟功能应用示例

Python Tkinter模块实现时钟功能应用示例

本文实例讲述了Python Tkinter模块实现时钟功能。分享给大家供大家参考,具体如下: 本机测试效果: 完整代码: # coding=utf-8 from Tkinter i...

python网络编程学习笔记(五):socket的一些补充

1、半开放socket 利用shutdown()函数使socket双向数据传输变为单向数据传输。shutdown()需要一个单独的参数,该参数表示了如何关闭socket。具体为:0表示禁...

python如何将多个PDF进行合并

背景 由于工作性质,经常面对不同的问题,某些场景下SQL+Excel、常用办公软件不能处理,这时到网上找一些案例,自己动手用python处理。后续,借此博客记录比较典型的处理过程。...

python钉钉机器人运维脚本监控实例

python钉钉机器人运维脚本监控实例

如下所示: #!/usr/bin/python3 # -*- coding:UTF-8-*- # Author: zhuhongqiang from urllib impor...

python使用minimax算法实现五子棋

这是一个命令行环境的五子棋程序。使用了minimax算法。 除了百度各个棋型的打分方式,所有代码皆为本人所撸。本程序结构与之前的井字棋、黑白棋一模一样。 有一点小问题,没时间弄了,就这样...