在python中获取属性的属性

时间:2015-10-14 05:45:40

标签: python python-decorators

我有一个装饰器,它只是缓存返回值(在我的例子中称为@cached),我希望将它与@property结合使用。这通常很好。当我尝试使用expire添加的@cached属性时,我遇到了问题。

def cached(f):
    cache = [None]

    def inner(*args, **kwargs):
        if cache[0]:
            cache[0] = f(*args, **kwargs)
        return cache[0]

    def expire():
        cache[0] = None

    inner.expire = expire
    return inner

class Example(object):
    @property
    @cached
    def something_expensive(self):
        print("expensive")
        return "hello"


e = Example()
e.something_expensive
e.something_expensive.expire()

我如何才能访问过期功能?在被@property替换后添加到函数中。我理解为什么这不起作用我对解决这个问题的方法很感兴趣。

一些限制:

  • 我无法在我无法控制的库中更改@cached装饰器
  • 我真的不想删除@property,因为我希望在单元测试中过期,它们使我的代码更好用。

我认为一个相当糟糕的解决方案是(因为实际上我有很多属性,我想这样做):

class Example(object):
    @cached
    def _something_expensive(self):
        return "hello"

    @property
    def something_expensive(self):
        return self._something_expensive()

1 个答案:

答案 0 :(得分:2)

您可以使用类字典访问它:

type(e).__dict__['something_expensive'].fget.expire()

一般来说,e.something_expensive相当于:

type(e).__dict__['something_expensive'].__get__(e, type(e))

有关详细信息,请阅读:Descriptor HowTo Guide

请注意,在expiry函数中,您没有将cache从外部函数cached函数设置为None,您只需创建一个新的局部变量。你可能想做这样的事情:

def expire():
    del cache[:]
    cache.append(None)

在Python 3中,使用nonlocal关键字更新cache更加容易。