我的IDE已经"更正了" 我的代码,用于将函数(和其他代码)转换为属性。我担心这可能效率低下。
@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。我知道,这种想法促成了这个问题。
答案 0 :(得分: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 :(得分:1)
实际上,每次都会调用该属性。这不是一个很好的财产使用;调用者希望它不会比属性访问花费更长的时间。
Pyramid中有一个名为reify
的可爱装饰器,它第一次调用该函数,然后将该值设置为对象上的同名属性,以便下次使用先前计算的值。 / p>
如果您不想仅仅为一个装饰器使用Pyramid,您可以使用我写的这个版本(它的工作方式类似于金字塔,但我是独立编写的):
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