66

関数を条件付きでデコレータすることは可能ですか?たとえば、関数foo()をタイマー関数(timeit)で装飾したいのはdoing_performance_analysisだけですTrue(以下の疑似コードを参照)。

if doing_performance_analysis:
  @timeit
  def foo():
    """
    do something, timeit function will return the time it takes
    """
    time.sleep(2)
else:
  def foo():
    time.sleep(2)  
4

6 に答える 6

81

デコレータは、置換、オプションで同じ関数、ラッパー、またはまったく異なるものを返す単純な呼び出し可能オブジェクトです。そのため、条件付きデコレータを作成できます。

def conditional_decorator(dec, condition):
    def decorator(func):
        if not condition:
            # Return the function unchanged, not decorated.
            return func
        return dec(func)
    return decorator

これで、次のように使用できます。

@conditional_decorator(timeit, doing_performance_analysis)
def foo():
    time.sleep(2)  

デコレータはクラスにすることもできます。

class conditional_decorator(object):
    def __init__(self, dec, condition):
        self.decorator = dec
        self.condition = condition

    def __call__(self, func):
        if not self.condition:
            # Return the function unchanged, not decorated.
            return func
        return self.decorator(func)

ここで、__call__メソッドは最初の例で返されたネストされた関数と同じ役割を果たし、ここdecorator()でのクローズドオーバーdecconditionパラメーターは、デコレーターが適用されるまでインスタンスの引数として格納されます。

于 2012-05-23T17:24:08.507 に答える
18

デコレータは、単に別の関数に適用される関数です。手動で適用できます。

def foo():
   # whatever
   time.sleep(2)

if doing_performance_analysis:
    foo = timeit(foo)
于 2012-05-23T17:23:07.853 に答える
9

どうですか:

def foo():
   ...

if doing_performance_analysis:
   foo = timeit(foo)

これをブールフラグと別のデコレータを使用するデコレータにラップすることもでき、フラグが次のように設定されている場合にのみ後者を適用できると思いますTrue

def cond_decorator(flag, dec):
   def decorate(fn):
      return dec(fn) if flag else fn
   return decorate

@cond_decorator(doing_performance_analysis, timeit)
def foo():
   ...
于 2012-05-23T17:22:10.050 に答える
3
use_decorator = False

class myDecorator(object):
    def __init__(self, f):
            self.f = f

    def __call__(self):
            print "Decorated running..."
            print "Entering", self.f.__name__
            self.f()
            print "Exited", self.f.__name__


def null(a):
    return a


if use_decorator == False :
    myDecorator = null


@myDecorator
def CoreFunction():
    print "Core Function running"

CoreFunction()
于 2016-09-17T00:10:41.150 に答える
1

Blckknghtの答えは、関数を呼び出すたびにチェックを実行したい場合に最適ですが、一度読み取ることができ、変更されない設定がある場合は、装飾された関数が呼び出されるたびに設定をチェックしたくない場合があります。動作中の高性能デーモンのいくつかでは、Pythonファイルが最初にロードされたときに設定ファイルを一度チェックし、それをラップするかどうかを決定するデコレーターを作成しました。

これがサンプルです

def timed(f):
    def wrapper(*args, **kwargs):
        start = datetime.datetime.utcnow()
        return_value = f(*args, **kwargs)
        end = datetime.datetime.utcnow()
        duration = end - start

        log_function_call(module=f.__module__, function=f.__name__, start=__start__, end=__end__, duration=duration.total_seconds())
    if config.get('RUN_TIMED_FUNCTIONS'):
        return wrapper
    return f

log_function_callがデータベースやログファイルなどへの呼び出しをログに記録し、config.get('RUN_TIMED_FUNCTIONS')がグローバル構成をチェックし、@ timedデコレーターを関数に追加すると、ロード時に1回チェックして、タイミングが合っているかどうかを確認します。このサーバー、環境など。そうでない場合は、本番環境またはパフォーマンスが重要なその他の環境での関数の実行は変更されません。

于 2014-01-16T22:15:11.937 に答える
0

これが私のために働いたものです:

def timeit(method):
    def timed(*args, **kw):
        if 'usetimer' not in kw:
            return method(*args, **kw)
        elif ('usetimer' in kw and kw.get('usetimer') is None):
            return method(*args, **kw)
        else:
            import time
            ts = time.time()
            result = method(*args, **kw)
            te = time.time()
            if 'log_time' in kw:
                name = kw.get('log_name', method.__name__.upper())
                kw['log_time'][name] = int((te - ts) * 1000)
            else:
                print '%r took %2.2f ms' % \
                      (method.__name__, (te - ts) * 1000)
            return result
    return timed

def some_func(arg1, **kwargs):
    #do something here

some_func(param1, **{'usetimer': args.usetimer})
于 2018-11-21T14:23:27.190 に答える