Python 如何为属性的延迟初始化创建装饰器
我想创建一个类似于属性的装饰器,它只调用装饰函数一次,在后续调用中总是返回第一次调用的结果。例如:Python 如何为属性的延迟初始化创建装饰器,python,decorator,descriptor,lazy-initialization,Python,Decorator,Descriptor,Lazy Initialization,我想创建一个类似于属性的装饰器,它只调用装饰函数一次,在后续调用中总是返回第一次调用的结果。例如: def SomeClass(object): @LazilyInitializedProperty def foo(self): print "Now initializing" return 5 >>> x = SomeClass() >>> x.foo Now initializing 5 >>&
def SomeClass(object):
@LazilyInitializedProperty
def foo(self):
print "Now initializing"
return 5
>>> x = SomeClass()
>>> x.foo
Now initializing
5
>>> x.foo
5
我的想法是为它写一个定制的装饰。所以我开始了,这就是我取得的成就:
class LazilyInitializedProperty(object):
def __init__(self, function):
self._function = function
def __set__(self, obj, value):
raise AttributeError("This property is read-only")
def __get__(self, obj, type):
# problem: where to store the value once we have calculated it?
正如您所看到的,我不知道在哪里存储缓存的值。最简单的解决方案似乎只是维护一本字典,但我想知道是否有更优雅的解决方案
编辑很抱歉,我忘了提到我希望属性是只读的。是一个方法修饰符,它使属性变懒(计算一次,可访问多次)。为了使它也是只读的,我添加了一个\uuuuuuuuuuu
方法。为了保留重新计算的能力(见下文),我添加了一个\uuuuu delete\uuuu
方法:
class ReadOnlyCachedAttribute(object):
'''Computes attribute value and caches it in the instance.
Source: Python Cookbook
Author: Denis Otkidach https://stackoverflow.com/users/168352/denis-otkidach
This decorator allows you to create a property which can be computed once and
accessed many times. Sort of like memoization
'''
def __init__(self, method, name=None):
self.method = method
self.name = name or method.__name__
self.__doc__ = method.__doc__
def __get__(self, inst, cls):
if inst is None:
return self
elif self.name in inst.__dict__:
return inst.__dict__[self.name]
else:
result = self.method(inst)
inst.__dict__[self.name]=result
return result
def __set__(self, inst, value):
raise AttributeError("This property is read-only")
def __delete__(self,inst):
del inst.__dict__[self.name]
例如:
if __name__=='__main__':
class Foo(object):
@ReadOnlyCachedAttribute
# @read_only_lazyprop
def bar(self):
print 'Calculating self.bar'
return 42
foo=Foo()
print(foo.bar)
# Calculating self.bar
# 42
print(foo.bar)
# 42
try:
foo.bar=1
except AttributeError as err:
print(err)
# This property is read-only
del(foo.bar)
print(foo.bar)
# Calculating self.bar
# 42
CachedAttribute
(和
ReadOnlyCachedAttribute)是指如果您del foo.bar
,则下次
访问foo.bar
,重新计算该值。(这种魔法是由
del foo.bar
从foo.\uuu dict\uuuu
中删除'bar'
,但属性
条形图
仍保留在Foo.\uu dict\uuu
)
如果您不需要或不希望此功能重新计算,
然后,以下(基于)是创建只读惰性属性的更简单方法
def read_only_lazyprop(fn):
attr_name = '_lazy_' + fn.__name__
@property
def _lazyprop(self):
if not hasattr(self, attr_name):
setattr(self, attr_name, fn(self))
return getattr(self, attr_name)
@_lazyprop.setter
def _lazyprop(self,value):
raise AttributeError("This property is read-only")
return _lazyprop
谢谢你。我只是编辑了我的问题,添加了一个我忘记的要求。我怎样才能使它成为只读的?这可能重复了我的问题:你是对的。没有在建议框中看到它。投票结束。