2013-12-17 42 views
2

我的IDE有“更正”我的代码将函数(和其他代码)转换为属性。我担心这可能是低效的。@properties装饰器缓存结果吗?

@property 
def output_all_children(self): 
    lh = ListHolder() 
    traverse_directories(self.start_directory, lh) 
    return lh.internal_list 

这会造成一些繁重的I/O升降,需要一些时间。我想知道如果这是不正确的,由于效率的原因。我想知道如果结果不像我希望会发生的那样缓存。

如果这个属性被访问好几次,它会重建并每次返回lh.internal_list? 我会更改self.start_directory更改类级别变量并更新它。

我看过这样的: How to create decorator for lazy initialization of a property它是指一个只读属性而我将是一个更新的属性

请盲目信任的IDE任何评论。我知道,这种想法引发了这个问题。

回答

3

不,属性只是将属性访问转换为函数调用。没有自动缓存发生。

换句话说,语法instance.output_all_children为您翻译为instance.output_all_children()

您可以轻松地将某些缓存添加到属性方法,或者您可以重新使用您的问题中链接的代码;如果您愿意,只需替换__set__方法来处理属性分配。

添加一些缓存:

_output_all_children = None 

@property 
def output_all_children(self): 
    if self._output_all_children is None: 
     lh = ListHolder() 
     traverse_directories(self.start_directory, lh) 
     self._output_all_children = lh.internal_list 
    return self._output_all_children 
1

事实上,物业每次都会被调用。这不是一个很好的财产使用;调用者会期望它不会比属性访问长得多。

金字塔中有一个名为reify的可爱装饰器,它第一次调用该函数,然后将该值设置为该对象上的同名命名属性,以便下一次使用之前计算的值。

如果你不想使用金字塔只是一个装饰,你可以使用这个版本我写的(它就像金字塔的,但我单独写):

import functools 

def reify(func): 

    class Descriptor(object): 
     def __get__(self, inst, type=None): 
      val = func(inst) 
      setattr(inst, func.__name__, val) 
      return val 

    return functools.wraps(func)(Descriptor()) 

要使它很好地工作与您的使用案例,只需del属性关闭实例时,您需要重新计算它:

@reify 
def all_children(self): 
    lh = ListHolder() 
    traverse_directories(self.start_directory, lh) 
    return lh.internal_list 

# for internal use only, call when a cached all_children may no longer be valid 
def _invalidate_all_children(self): 
    try: 
     del self.all_children 
    except AttributeError: 
     pass