不确定这是否是一个正确的问题,但这就是问题所在。
我有一个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
有没有办法实现这个目标?它甚至是一种有效的使用方式吗?
答案 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装饰器当前是怎么回事,很难确切地知道它是如何工作的,或者它将如何与其他装饰器交互操作。)