1

これは楽しい日曜日の朝の問題だと思いました。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
4

0 に答える 0