python __getattr__, __setattr__ 和 __getattribute__

获取和设置对象相关属性时常用的三个魔法方法

__getattr__(self, item)

在访问对象的 item 属性且 item 属性不存在时会调用此方法,如果对象已经有 item 这个属性了,则不会调用这个方法,会直接返回对象的 item 属性

__setattr__(self, item, value)

在试图为对象的 item 属性赋值的时候会被调用

__getattribute__(self, item)

访问对象的任何属性,不管存不存在,都会调用此方法

特别注意:重写这些方法的时候需要特别小心,很容易引起死递归

下面是一个会引起死递归的示例

class Loop(object):
    def __init__(self, data):
        self._data = data

    def __getattribute__(self, name):
        print 'do something'
        return self._data[name]

问题的关键在于:在 __getattribute__ 中访问了 _data 属性,而访问 _data 属性同样会被__getattribute__ 方法拦截,这样就造成了无限递归

File "loop.py", line 11, in __getattribute__
    return self._data[name]
RuntimeError: maximum recursion depth exceeded while calling a Python object

要想在 __getattribute__ 访问某个属性,正确的做法是从实例的属性字典直接获取 _data 的属性值,以避免无限递归

class RightWay(object):
    def __init__(self, data):
        self._data = data

    def __getattribute__(self, name):
        print 'do something'
        data = super(RightWay, self).__getattribute__('_data')
        return data[name]

同样的,如果要在 __setattr__ 方法中修改对象的属性,也需要通过 super().__setattr__来完成

posted @ 2017-07-31 13:00  天涯海角路  阅读(182)  评论(0)    收藏  举报