Python 动态分配对象/dict方法,该方法在首次访问时用函数结果覆盖自身

Python 动态分配对象/dict方法,该方法在首次访问时用函数结果覆盖自身,python,caching,optimization,memoization,Python,Caching,Optimization,Memoization,我想这将是一个有趣的周日早上的问题。已经三个小时了,我离这里还很远 背景: 我正在使用dogpile缓存SqlAlchemy中的只读数据 我将一行数据转换为名为objectifieddit的dict的自定义子类。这让我可以用对象表示法处理dict,这样我就可以像处理活动的SqlAlchemy对象一样,为这些只读dict使用相同的模板和帮助程序。(我也喜欢将缓存数据存储为dict,这样我就可以将相同的缓存值用于其他应用程序或语言) 一切都很顺利 我一直在探索提高缓存性能的方法,还记得Pyramid

我想这将是一个有趣的周日早上的问题。已经三个小时了,我离这里还很远

背景:

我正在使用
dogpile
缓存
SqlAlchemy
中的只读数据

我将一行数据转换为名为
objectifieddit
dict的自定义子类。这让我可以用对象表示法处理dict,这样我就可以像处理活动的SqlAlchemy对象一样,为这些只读dict使用相同的模板和帮助程序。(我也喜欢将缓存数据存储为dict,这样我就可以将相同的缓存值用于其他应用程序或语言)

一切都很顺利

我一直在探索提高缓存性能的方法,还记得Pyramid的
@reify
decorator()@reify允许对象方法用function的返回值覆盖自身,这样底层函数只调用一次。出于缓存的目的,这个想法对我很有吸引力

[如评论中所述,备忘录是一个更恰当的术语]

问题:

我不知道如何最好地处理这样的事情。尝试动态设置对象属性以重新定义它们自己比我想象的要困难得多
@reify
非常简单,而且工作非常好,因为它位于预定义的类上

到目前为止,我想到的最好的是这个

class ReifiedObjectFunction(object):
    def __init__(self, object , object_attribute, function , *args , **kwargs ):
        self.object = object
        self.object_attribute = object_attribute
        self.function = function
        self.args = args
        self.kwargs = kwargs
        try:
            self.__doc__ = function.__doc__
        except: # pragma: no cover
            pass
    def __repr__(self):
        val = self.function(*self.args,**self.kwargs)
        setattr( self.object , self.object_attribute , val )
        return val


class ObjectifiedDict(dict):
    def __getattr__(self,attr):
        if attr in self:
            return self[attr]
        return self.__getattribute__(attr)
    def lazyload( self, attr , function , *args , **kwargs ):
        self[attr] = ReifiedObjectFunction(self,attr,function,*args,**kwargs)


def lazyloaded_function(*args,**kwargs):
    print 'compute lazyloaded_function %s,%s' % ( args , kwargs )
    return "%s" % args


sample = ObjectifiedDict({'a':'a','b':'bb','c':'ccc'})
print "get a"
print "     %s" % sample.a
print "get b"
print "     %s" % sample.b
print "set d"
sample.lazyload( 'd' , lazyloaded_function , "dddd" )
print "d is set"
print "sample : %s" % sample
print "get d"
print "     %s" % sample.d
print "get d again"
print "     %s" % sample.d
print "sample : %s" % sample
不过,这有几个明显而巨大的警告。它只适用于字符串上下文(因为我正在重载repr),并且只能返回字符串值

有人知道我该怎么做吗

更新:

我想出了这个我想做的工作的例子。是否有人认为这种方法存在任何问题:

class LazyloadedFunction(object):

    def __init__(self, object , object_attribute, function , *args , **kwargs ):
        self.object = object
        self.object_attribute = object_attribute
        self.function = function
        self.args = args
        self.kwargs = kwargs
        try:
            self.__doc__ = function.__doc__
        except: # pragma: no cover
            pass

    def execute(self):
        val = self.function(*self.args,**self.kwargs)
        return val


class ObjectifiedDict(dict):

    def __getitem__(self,attr):
        if attr in self:
            item = dict.__getitem__(self,attr)
            if isinstance( item , LazyloadedFunction ):
                item = item.execute()
                dict.__setitem__( self , attr , item )
            return item

    def __getattr__(self,attr):
        if attr in self:
            if isinstance( self[attr] , LazyloadedFunction ):
                self[attr] = self[attr].execute()
            return self[attr]
        return self.__getattribute__(attr)

    def __getattribute__(self,attr):
        return dict.__getattribute__(self,attr)

    def lazyload( self, attr , function , *args , **kwargs ):
        self[attr] = LazyloadedFunction(self,attr,function,*args,**kwargs)


def lazyloaded_function(*args,**kwargs):
    print 'compute lazyloaded_function %s,%s' % ( args , kwargs )
    return [1,2,3]


sample_a = ObjectifiedDict({'a':'a','b':'bb','c':'ccc'})
sample_a.lazyload( 'd' , lazyloaded_function , "dddd" )

sample_b = ObjectifiedDict({'a':'a','b':'bb','c':'ccc'})
sample_b.lazyload( 'd' , lazyloaded_function , "dddd" )

print "sample_a"
print sample_a
print "sample_a.d = %s" % sample_a.d
print sample_a

print "====="

print "sample_b"
print sample_b
print "sample_b['d'] = %s" % sample_b['d']
print sample_b

这不只是记忆吗?记忆是个更好的术语。我用的是金字塔法的物化。我将调整问号和标签。