更改子类中的装饰器参数

时间:2014-02-20 06:38:18

标签: python python-2.x python-decorators

不确定这是否是一个正确的问题,但这就是问题所在。

我有一个memoized装饰器(作为一个类实现)。装饰器接受一个与缓存大小相关的参数。我希望我的DB模型类都有一个搜索方法,所以我写了一个mixin(我认为它是一个mixin)

class SearchMixin(object): 
    @classmethod
    @memoized(100)
    def search(cls,session,**kwargs): 
        q = session.query(cls)
        for k,v in kwargs.items(): 
            q = q.filter(getattr(cls,k,None).__eq__(v))
        res = q.one()
        return res

在我的模特中,

class ModelA(Base,SearchMixin): 
    foo = Column()
    bar = Column() 
    #And so on

现在我可以执行ModelA.search(foo=x,bar=y)并且memoized decorator工作并且如果之前已经询问相同的查询则从缓存返回。

问题在于,对于某些模型,我需要更改某些搜索的缓存大小(100中的defualt SearchMixin。我可以用装饰器的不同参数重新编写搜索功能

class ModelB(Base): 
    @classmethod
    @memoized(5)
    def search(cls,session,**kwargs): 
        #Search method for my modelB

但这违背了编写mixin的目的(删除代码重复)。

我理想的是

class ModelB(Base,SearchMxin): 
    foo1 = Column()
    bar1 = Column()
    cache_size = 5 
    #Some magic
    #Now I don't need to rewrite the search function with a different argument

有没有办法实现这个目标?它甚至是一种有效的使用方式吗?

1 个答案:

答案 0 :(得分:3)

以下是一种方式草图:

def deco(func):
    def newFunc(cls, *args, **kw):
        print "Decorated function using cache size", cls.cache_size
        return func(cls, *args, **kw)
    return newFunc

class Foo(object):
    cache_size = 10

    @classmethod
    @deco
    def meth(cls):
        print "Foo.meth()"

class Bar(Foo):
    cache_size = 20

>>> Foo.meth()
Decorated function using cache size 10
Foo.meth()
>>> Bar.meth()
Decorated function using cache size 20
Foo.meth()

我不确切知道你的memoization装饰器做了什么,所以这个例子只使用了一个虚拟装饰器。但是这个想法应该是明确的:编写你的装饰器,使它在类上查找其缓存大小,而不是将缓存大小作为参数传递。

只是为了澄清一些事情:在您的示例中,当您在search上创建SearchMixin方法并应用@memoize(100)时,“原始”搜索方法 - 即未修饰的没有记忆的版本---实际上不再存在。如果在装饰器调用时修复了高速缓存大小,则无法通过分配类变量来回到内部并稍后更改它。最终,您需要以某种方式重构装饰器,以便从某些外部源(例如,类)检索所需的高速缓存大小。

(如果你的memoization装饰器实际上是一个类,它可能会使它更聪明和更狡猾,所以它会注意到它是“重新装饰”已经用同一个装饰器包装的方法。例如,memoization类可以修改其内部缓存大小变量,而不是添加另一层包装。但是,如果不知道你的memoization装饰器当前是怎么回事,很难确切地知道它是如何工作的,或者它将如何与其他装饰器交互操作。)