2016-05-23 8 views
1

デコレータを使用して関数を実行すると、デコレータ呼び出しを呼び出さずに関数を実行することができますか?デコレータをオプションでオンまたはオフにする方法

与えられた関数fooは、オプションでデコレータをオンまたはオフにできますか?

@decorator 
def foo(): 
    //do_somthing 

考える

はそれがオフになってdecoratorで可能な走行fooですか?

デコレータの有無にかかわらず実行したい場合があります。たとえば、効率的なキャッシングが必要なため、良い方法ではないので、factorial(n)関数でデコレータベースのキャッシングをオフにします。

私の質問はこの質問Optionally use decorators on class methodsと似ています。デコレータ切り替えのON/OFF(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

ヒント:レビューアがあなたの変更のコメントを参照してください、あなたは幼稚園児があなたの質問を再開するためにそれらをやる気にさせる良い方法ではないようにコミュニティにダウン話す必要が暗示しています。また、実行時にデコレーションをオフにするメカニズムを使用することを受け入れるでしょうか?デコレータにdebugFlagが有効になっているかどうか調べます。有効になっていなければ、デコレータ関数をダミーのラッパーに置き換えます。これは少しオーバーヘッドがありますが、もっとエキゾチックなものを考え出すのには十分ではありません(しかし、私はただ一つのデコレータと多くはありません)。 – Foon

+0

@Foon私たちは皆、お互いを助けようとしています。利益。私が複雑な/厄介な状況を作り、それを幼稚園レベルにダムすることができれば、私は事を説明する上で素晴らしい仕事をしたと思います。 。この質問が表示されるたびに、私はそれをあまりにも愚かにしようとします。それがあなたにとって理にかなっているなら、この視点を試してみてください。将来的には、勤勉で尊敬できるコミュニティを馬鹿げた印象を持たないことを願っています。 はい、私はすべての入力/改善を受け入れます。 '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

関連する問題