2016-05-23 3 views
1

Я спрашиваю, с помощью функции с декоратором, можно ли запустить функцию без вызова вызова декоратора?Как сделать декораторы необязательно включать или выключать

С учетом функции foo, можно ли по желанию включить или выключить декоратор на нем?

Учитывая

@decorator 
def foo(): 
    //do_somthing 

Можно ли запустить foo с decorator Выключен?

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

Мой вопрос похож на этот вопрос Optionally use decorators on class methods. В нем обсуждается хорошее применение включения/выключения декоратора (экспозиция как api);

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

# this is the decorator class that executes the function `goo` 
class deco(object): 
    def __init__(self, attr): 
     print "I am initialized" 
     self.fn = None 
     # some args you may wana pass 
     self.attr = attr 
     # lets say you want these attributes to persist 
     self.cid = self.attr['cid'] 
     self.vid = 0 

    def __call__(self, f): 
     # the call executes and returns another inner wrapper 
     def wrap(*args): 
      # this executes main function - see closure 
      self.fn = f 
      self.vid = args[0] 
      self.closure(*args) 
     return wrap 

    def closure(self, *args): 
     n = args[0] 
     self.cid[n] = self.vid 
     #goo = deco(fn, attr) 
     print 'n',n 
     # executes function `goo` 
     self.fn(*args) 


class gooClass(object): 
    class that instantias and wraps `goo`around 
    def __init__(self, attr, deco): 
     ''' 
     @param: 
       - attr: some mutable data structure 
       - deco: True or False. Whether to run decorator or not 
     ''' 
     self.attr = attr 
     self.deco = deco 

    def __call__(self, *args): 
     if self.deco: 
      # initiate deco class with passed args 
      foo = deco(self.attr) 
      # now pass the `goo` function to the wrapper inside foo.__class__.__call__ 
      foo = foo(self.goo) 
      return foo(*args) 
     else: 
      # execute w/o decorator 
      return self.goo(*args)       

    def goo(self, n): 
     # recursive goo 
     if n>0: 
      print 'in goo',n 
      #print n 
      # to recurse, I recreate the whole scene starting with the class 
      # because of this the args in `deco` Class init never persist 
      too = gooClass(self.attr, self.deco) 
      return too(n-1) 
     else: return n 


def Fn(n, decoBool): 
    # this function is where to start running from 
    attr = {} 
    cid = [0]*(n+1) 
    attr['cid'] = cid 

    #following wud work too but defeat the purpose - have to define again! foo is goo actually 
    #@deco(attr) 
    #def foo(n): 
    # if n>0: 
    #  print 'in foo',n 
    #  #print n 
    #  return foo(n-1) 
    # else: return n 
    #return foo(n), attr 
    # create the gooClass and execute `goo` method instance 
    foo = gooClass(attr, decoBool) 
    print foo(n) 
    return foo 



res = Fn(5, True) 
print res.attr 
print "="*10 
res = Fn(5, False) 
print res.attr 

, который выводит:

I am initialized 
n 5 
in goo 5 
I am initialized 
n 4 
in goo 4 
I am initialized 
n 3 
in goo 3 
I am initialized 
n 2 
in goo 2 
I am initialized 
n 1 
in goo 1 
I am initialized 
n 0 
None 
{'cid': [0, 1, 2, 3, 4, 5]} 
========== 
in goo 5 
in goo 4 
in goo 3 
in goo 2 
in goo 1 
0 
{'cid': [0, 0, 0, 0, 0, 0]} 

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

Вопрос стоит, и я не мог найти здесь одного релевантного ответа, поэтому я создал это, есть ли способ включить или отключить Декораторы?

+0

Подсказка: рецензенты видеть ваше изменение комментарий и подразумевающее вы должны говорить вплоть до SO сообщества детсадовцев не является хорошим способом, чтобы мотивировать их заново на ваш вопрос. Кроме того, вы согласитесь, что у вас есть механизм, чтобы отключить декор во время выполнения? У меня есть что-то, где в моем декораторе я ищу, что debugFlag включен; если он не включен, я заменю мою функцию декоратора фиктивной оберткой. У этого есть небольшое количество накладных расходов, но недостаточно для того, чтобы попытаться придумать что-то более экзотическое (но это помогает, что у меня есть только один декоратор и немного) – Foon

+0

@Foon Мы все пытаемся помочь друг другу и очень выгода. Если я смогу сделать сложную/беспорядочную ситуацию, а Dumb это до уровня детского сада, я думаю, что я сделал Великую работу, объясняя вещи. , Каждый раз, когда я вижу этот вопрос, я стараюсь его опустить. Если это имеет смысл для вас, попробуйте эту перспективу. Надеюсь, в будущем у вас не будет впечатления о том, что я высмеиваю любое трудолюбивое уважаемое сообщество. Да, я согласен с любыми входами и импровизациями. Проверьте 'decoBool' и' deco' - в моем коде это ваш debugFlag? – user2290820

+0

Я постараюсь добавить в код некоторые вспомогательные документы/комментарии. Это будет полезно, но здесь слишком поздно. Я сделаю это завтра. – user2290820

ответ

3

Прикрепите неподтвержденную функцию к украшенной, как говорят unwrapped, прежде чем вернуть ее из декоратора.

Например

def add42(fn): 
    def wrap(i): 
     return fn(i) + 42 
    wrap.unwrapped = fn 
    return wrap 

@add42 
def mult3(i): 
    return i * 3 

mult3(1) # 45 
mult3.unwrapped(1) # 3 
+0

это очень хороший взлом! – user2290820

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