2014-02-20 1 views
0

Не уверен, что это даже правильный вопрос, но вот проблема.Изменение аргументов декоратора в подклассах

У меня есть памятный декоратор (выполненный как класс). Декоратор принимает аргумент, размер кеша. Я хочу, чтобы мои DB классы модели для каждого есть метод поиска, поэтому я написать подмешать (я думаю, что это 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 работает и возвращается из кеша, если тот же запрос был задан раньше.

Проблема в том, что для некоторых моделей мне нужно изменить размер кеша для некоторых поисков (то есть defualt 100 в SearchMixin). Я могу переписать функцию поиска с другим аргументом для декоратора

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

но побеждает цель написания подмешать (удаление дублирования кода).

Что я хочу идеально

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

Вы можете сделать это, написав другой декоратор воспоминаний, который считывает свой размер кеша из атрибута класса при его вызове, вместо этого читая его из аргумента, когда он определен. – BrenBarn

ответ

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

Я не знаю точно, что делает ваше запоминание декоратор, поэтому этот пример использует только фиктивный декоратор. Но идея должна быть ясной: напишите свой декоратор, чтобы он смотрел на класс для его размера кеша, вместо того, чтобы передавать размер кеша в качестве аргумента.

Просто чтобы прояснить кое-что: в вашем примере, при создании метода search на SearchMixin и применять @memoize(100), «оригинал» поиска метода --- то есть, недекорированного версии не запоминанием --- эффективно больше не существует , Если размер кэша фиксируется во время вызова декоратора, вы не можете вернуться внутрь и изменить его позже, просто назначив переменную класса. В конечном итоге вам нужно каким-то образом реорганизовать декоратор, чтобы он извлекал нужный размер кеша из какого-то внешнего источника (например, класса).

(Если ваш декоратор напоминания фактически является классом, возможно, он станет более умным и хитрым, чтобы он заметил, что это «ремонт» метода, который уже был обернут одним и тем же декоратором. случай, класс memoization мог бы изменить свою внутреннюю переменную размера кэша вместо добавления другого слоя обертки. Однако трудно точно сказать, как это будет работать, или как оно будет взаимодействовать с другими декораторами, не зная о том, как ваш декоратор напоминания в настоящее время работает.)

+0

Это хорошая идея. Но мой декоратор - это класс (а не функция) и принимает еще несколько параметров (отладка и прочее). Его можно использовать и для произвольных функций (а не только для методов класса). В настоящее время я не передаю класс декоратору (только функция) – RedBaron

+1

@RedBaron: Если у вас есть другие ограничения на ваш декоратор, вам нужно будет отредактировать свой вопрос, чтобы объяснить их.Решение, которое я дал здесь, может быть легко выполнено с использованием класса вместо функции и может принимать дополнительные параметры. Тем не менее, я не думаю, что есть большая надежда написать декоратор, который работает для методов класса и автономных функций, но все же смотрит на класс, чтобы узнать его размер кеша. Если вы хотите, чтобы декоратор использовал переменную класса, например 'cache_size', декоратор должен иметь некоторую степень интеграции с классом. – BrenBarn