2013-04-16 3 views
2

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

using f 
using g 
using f 
using h 

Но теперь наступает мой вопрос. Как это сделать, чтобы не дублировать зависимости? Итак, когда я использую h(), f() будет вызываться только один раз? Я попытался удалить дубликаты форм, но, например, для h() он содержит wapper и f(). Должен ли я собирать их по-другому?

class depends(object): 
    functs = [] 
    def __init__(self, *f): 
     self.functs = [] 
     for i in f: 
      self.functs.append(i) 

    def __call__(self, fun): 
     def wrapper(): 
      for i in self.functs: 
       i() 

      return fun() 
     return wrapper 

def f(): 
    print 'using f' 

@depends(f) 
def g(): 
    print 'using g' 

@depends(g, f) 
def h(): 
    print 'using h' 

h() 

ответ

3

Python уже есть что-то вроде этого уже встроен в его super вызывающего механизма. Однако, чтобы воспользоваться super, вы должны превратить вашу зависимость в базовые классы:

def depends(*deps): 
    def deco(func): 
     def __new__(self): 
      super(Dependency, self).__new__(self) 
      return func() 
     Dependency = type('Dependency', deps, {'__new__': __new__}) 
     return Dependency 
    return deco 


@depends(object) 
def f(): 
    print 'using f' 


@depends(f) 
def g(): 
    print 'using g' 


@depends(g, f) 
def h(): 
    print 'using h' 

h() 
# using f 
# using g 
# using h 
+1

+1 очень элегантный – shx2

1

Вы должны помнить, обработанные зависимости глобально, например, в переменном классе, см depends.done здесь:

class depends(object): 
    done = [] 
    def __init__(self, *f): 
     self.functs = f 

    def __call__(self, fun): 
     def wrapper(): 
      for i in self.functs: 
       if i not in depends.done: 
        i() 
        depends.done.append(i) 

      return fun() 
     return wrapper 

def f(): 
    print 'using f' 

@depends(f) 
def g(): 
    print 'using g' 

@depends(g, f) 
def h(): 
    print 'using h' 

h() 
+0

Я бы сказал, что это должна быть переменная экземпляра, иначе вы можете использовать зависимости только один раз, глобально. – Ber

+0

Это то, что мне было нужно, не так ли? – piokuc

+0

... но у вас есть переменная класса, которая будет использоваться для всех экземпляров класса, т. Е. Для всех применений декоратора. Я не думаю, что это желаемое поведение. – Ber

0

Вы должны проверить погоду любой функции зависимостей оформлены таким образом, и исключить их зависимости от тех, для в настоящее время украшенная функция.

Эта проверка должна быть выполнена рекурсивно.

Это становится намного сложнее, если вы также используете другие декораторы.

Я действительно удивляюсь, почему и как эта конструкция используется.

Смежные вопросы