これは楽しい日曜日の朝の問題だと思いました。3時間経ちましたが、私はどこにも近づきません...
バックグラウンド:
dogpile
から読み取り専用データをキャッシュするために使用していSqlAlchemy
ます。
dict
データの行を、呼び出された のカスタム サブクラスに変換しObjectifiedDict
ます。これにより、dict をオブジェクト表記で扱うことができるので、アクティブな SqlAlchemy オブジェクトで行うのと同じテンプレートとヘルパーをこれらの読み取り専用 dict に使用できます。(キャッシュされたデータを辞書として保存するのも好きなので、他のアプリや言語で同じキャッシュされた値を使用できます)
すべてが完璧に機能しています。
私はキャッシングを少し改善する方法を模索しており、Pyramid の@reify
デコレーター ( http://docs.pylonsproject.org/projects/pyramid/en/latest/api/decorator.html ) を思い出しました。@reify を使用すると、オブジェクト メソッドは関数の戻り値で自分自身を上書きできます。このようにして、基になる関数は 1 回だけ呼び出されます。このアイデアは、キャッシングの目的で私にとって非常に魅力的です。
[コメントで述べたように、メモ化はより適切な用語です]
問題:
このようなものに最善のアプローチをする方法については、私は途方に暮れています。オブジェクトのプロパティを動的に設定してそれ自体を再定義しようとするのは、思ったよりも困難です。 @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