【问题标题】:Changing decorator arguments in sub-classes更改子类中的装饰器参数
【发布时间】:2014-02-20 06:38:18
【问题描述】:

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

我有一个 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) 并且如果之前已经询问过相同的查询,那么记忆化的装饰器就会工作并从缓存中返回。

问题在于,对于某些模型,我需要更改某些搜索的缓存大小(在 SearchMixin 中默认为 100)。我可以用装饰器的不同参数重写搜索函数

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

有什么方法可以实现吗?它甚至是一种有效的使用方式吗?

【问题讨论】:

  • 你可以通过编写一个不同的 memoization 装饰器来做到这一点,它在调用时从类属性中读取其缓存大小,而不是在定义时从参数中读取它。

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


【解决方案1】:

这是一种方式的草图:

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()

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

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

(如果你的 memoization 装饰器实际上是一个类,那么它可能会变得更聪明和更隐秘,这样它就会注意到它是否正在“重新装饰”一个已经用相同的装饰器包装的方法。在这样的在这种情况下, memoization 类可以修改其内部缓存大小变量而不是添加另一层包装. 但是, 很难确切地说这将如何工作, 或者它将如何与其他装饰器交互, 而不知道你的 memoization 装饰器当前如何运行。)

【讨论】:

  • 这是个好主意。但是我的装饰器是一个类(不是一个函数)并且接受更多的参数(调试和其他东西)。它也可以用于任意函数(不仅仅是类方法)。目前我没有将类传递给装饰器(只是函数)
  • @RedBaron:如果你对你的装饰器有其他限制,你需要编辑你的问题来解释它们。我在这里给出的解决方案可以很容易地使用类而不是函数来完成,并且可以接受额外的参数。但是,我认为编写一个适用于类方法和独立函数的装饰器的希望不大,但仍然会查看类以找出它的缓存大小。如果你想让装饰器使用像cache_size这样的类变量,装饰器需要与类有某种程度的集成。
猜你喜欢
  • 2022-08-15
  • 1970-01-01
  • 1970-01-01
  • 2016-09-13
  • 1970-01-01
  • 1970-01-01
  • 2011-11-21
  • 2012-08-18
  • 2023-04-04
相关资源
最近更新 更多