2015-10-14 72 views
1

我有一个装饰器,它只是缓存返回值(在我的示例中称为@cached),我希望将它与@property结合使用。这通常工作正常。我遇到的问题出现在我尝试使用由@cached添加的expire属性。获取python属性的属性

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() 

我如何才能访问expire函数?在被@property取代之后添加到该功能中。我明白为什么这不起作用我对解决该问题的方式感兴趣。

一些限制:

  • 我不能改变@cached装饰它在图书馆,我不控制
  • 我真的不想删除@property,因为我想在我的单元测试到期,他们做我的代码更好用。

一个解决方案,我认为是相当糟糕的是(因为在现实中,我有很多的属性,我想做到这一点的):

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

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

回答

2

您可以使用类字典访问:

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

一般而言e.something_expensive相当于:

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

有关详细信息读了起来:Descriptor HowTo Guide

注意,expiry功能你不从外部功能cached功能None设置cache里面,你只需创建一个新的局部变量。您可能需要做这样的事情:

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

在Python 3中使用nonlocal关键字更新cache更简单。

+0

非常感谢,我感谢帮助。缓存=无是一个打字错误的修复 – Nick