det*_*tly 106 python decorator
最近,我浏览了一个包含许多类的现有代码库,其中实例属性反映了存储在数据库中的值.我重构了很多这些属性,以便延迟数据库查找,即.不是在构造函数中初始化,而是仅在第一次读取时初始化.这些属性在实例的生命周期内不会发生变化,但它们是第一次计算的真正瓶颈,并且只在特殊情况下才真正访问过.因此,它们也可以在从数据库中检索后进行缓存(这因此符合记忆的定义,其中输入只是"无输入").
我发现自己一遍又一遍地为各种类的各种属性输入以下代码片段:
class testA(object):
def __init__(self):
self._a = None
self._b = None
@property
def a(self):
if self._a is None:
# Calculate the attribute now
self._a = 7
return self._a
@property
def b(self):
#etc
Run Code Online (Sandbox Code Playgroud)
是否有现成的装饰器已经在Python中执行此操作,我根本不知道?或者,是否有一种相当简单的方法来定义装饰器来执行此操作?
我在Python 2.5下工作,但如果它们有显着差异,2.6答案可能仍然很有趣.
在Python包含了大量现成的装饰器之前,人们已经提出了这个问题.我更新了它只是为了更正术语.
Mik*_*ers 123
这是一个惰性属性装饰器的示例实现:
import functools
def lazyprop(fn):
attr_name = '_lazy_' + fn.__name__
@property
@functools.wraps(fn)
def _lazyprop(self):
if not hasattr(self, attr_name):
setattr(self, attr_name, fn(self))
return getattr(self, attr_name)
return _lazyprop
class Test(object):
@lazyprop
def a(self):
print 'generating "a"'
return range(5)
Run Code Online (Sandbox Code Playgroud)
互动环节:
>>> t = Test()
>>> t.__dict__
{}
>>> t.a
generating "a"
[0, 1, 2, 3, 4]
>>> t.__dict__
{'_lazy_a': [0, 1, 2, 3, 4]}
>>> t.a
[0, 1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)
Cyc*_*one 108
我为自己写了这个...用于真正的一次性计算的懒惰属性.我喜欢它,因为它避免在对象上粘贴额外的属性,并且一旦激活就不会浪费时间检查属性存在等:
import functools
class lazy_property(object):
'''
meant to be used for lazy evaluation of an object attribute.
property should represent non-mutable data, as it replaces itself.
'''
def __init__(self, fget):
self.fget = fget
# copy the getter function's docstring and other attributes
functools.update_wrapper(self, fget)
def __get__(self, obj, cls):
if obj is None:
return self
value = self.fget(obj)
setattr(obj, self.fget.__name__, value)
return value
class Test(object):
@lazy_property
def results(self):
calcs = 1 # Do a lot of calculation here
return calcs
Run Code Online (Sandbox Code Playgroud)
注意:lazy_property该类是非数据描述符,这意味着它是只读的.添加__set__方法会阻止其正常工作.
guy*_*rad 11
对于各种伟大的实用程序,我正在使用boltons.
作为该库的一部分,您拥有cachedproperty:
from boltons.cacheutils import cachedproperty
class Foo(object):
def __init__(self):
self.value = 4
@cachedproperty
def cached_prop(self):
self.value += 1
return self.value
f = Foo()
print(f.value) # initial value
print(f.cached_prop) # cached property is calculated
f.value = 1
print(f.cached_prop) # same value for the cached property - it isn't calculated again
print(f.value) # the backing value is different (it's essentially unrelated value)
Run Code Online (Sandbox Code Playgroud)
property是一个类。准确地说是一个描述符。只需从中派生并实现所需的行为即可。
class lazyproperty(property):
....
class testA(object):
....
a = lazyproperty('_a')
b = lazyproperty('_b')
Run Code Online (Sandbox Code Playgroud)