2017-03-01 6 views
0

グローバルトグル変数を作成して、decoratorをオン/オフするコマンドラインで渡された引数に応じて変更したいと考えています。デコレータの使用方法をグローバルに切り替える

以下のケースでは、必要でないときに@time_md5_comparisonをコメントアウトする代わりに、渡された引数に応じてグローバルトグルが必要です。


main.py

from timing_decorator import time_md5_comparison 

@time_md5_comparison 
def md5_comparison(a, b): 
    if a==b: 
     return True 
    else: 
     return False 

timing_decorator.py

def time_md5_comparison(function): 
    @wraps(function) 
    def wrapper(*args, **kwargs): 
     t1 = time.time() 
     result = function(*args, **kwargs) 
     t2 = time.time() 
     print(str(function.__name__)+" "+ str("%.6f " %(t2 - t1))) 
     return result 
    return wrapper 

は、私が言って、変数を作成することができますUSE_DECORATORでmain.pyで=真その場合、デコレータが呼び出されます。 USE_DECORATOR = Falseの場合、元の関数が呼び出されます。

+3

質問は何ですか? – dav1d

+0

メインに変数USE_DECORATOR = Trueを作成できますか?py この場合、デコレータが呼び出されます。 USE_DECORATOR = Falseの場合、元の関数が呼び出されます。 – pmsuresh

+0

この答えを参照してください - http://stackoverflow.com/a/28654546/4497519コマンドラインから引数を使用して切り替えることは自明です。 –

答えて

0

デコレータはバイトコードに影響を与えるそれらの次の関数定義は、前である(実行とから分離しているときに発生しますコンパイルされた関数が呼び出されたときに実行されます)。したがって、装飾された関数をモジュール全体に再ロードすることが不十分です。おそらく、実行可能な唯一の方法は、フラグ変数の現在の設定に基づいてラップされた関数を異なる方法で実行させることです。

トグル変数は、変更可能なコンテナ(list)に入れなければならないことに注意してください。装飾された関数は、最初に装飾された時の値ではなく現在の値を参照します。単一機能以外の引数を取る


main.py

from timing_decorator import time_md5_comparison 

USE_DECORATOR = [False] 

@time_md5_comparison(USE_DECORATOR) 
def md5_comparison(a, b): 
    if a==b: 
     return True 
    else: 
     return False 

md5_comparison(3, 4) # prints nothing 
USE_DECORATOR[0] = True 
md5_comparison(5, 6) # prints timing info 

デコレータは、本質的に使用される実際のデコレータを作成して返す必要がありますデコレータ工場です。これは、あなたの質問のデコレータが一層深くネストされる必要があった理由です。


def time_md5_comparison(disabled): 
    def decorator(function): 
     @wraps(function) 
     def wrapped(*args, **kwargs): 
      if disabled[0]: 
       result = function(*args, **kwargs) 
      else: 
       t1 = time.time() 
       result = function(*args, **kwargs) 
       t2 = time.time() 
       print(str(function.__name__)+" "+ str("%.6f " %(t2 - t1))) 
      return result 

     return wrapped 

    return decorator 
+0

すばらしい説明!ありがとう@martineau – pmsuresh

+0

私は変数だけではなく、可変コンテナをなぜ使用するのかまだ分かりません。より良い理解を得るためにそれを試してみましょう。 – pmsuresh

+0

私も少し驚きましたが、 'True'や' False'のような組み込みのブール値は文字列と整数のように不変であるため、その値を関数に渡すと値は渡されませんthayは変更できないので、それらへの参照。 'list'の内容は変更可能ですので、参照によって渡されます。 – martineau

0

はい。値を渡すか、単にデコレータをリセットすることができます。

import timing_module 

if NO_USE_DECORATOR: 
    mydecorator = timing_module.empty_decorator 
else: 
    mydecorator = timing_module.time_md5_comparison 


@mydecorator 
def myfunc(args): 
    pass 

もちろん、あなたがそれmydecoratorを呼び出す必要はありません。

デコレータをリセットすると、このようなものになるだろう。代わりにtime_md5_comparisonの名前をリセットして、好きなものを指すようにすることができます。

引数がデコレータにロジックを入れ、クリーンであるように値を渡す:

#module: timing_module 
def original_time_md5_comparison(fn): 
    """Original code of your decorator here""" 
    # ... 
    pass 

def no_decorator(fn): 
    """Decorator no-op. Just use original function.""" 
    return fn 

def time_md5_comparison(use_decorator = True): 
    if use_decorator: 
     return original_time_md5_comparison 
    else: 
     return no_decorator 
関連する問題