как сделать условный декоратор в python 2.6

можно ли декоратору функцию условно. Например, я хочу украсить функцию foo() С функцией таймера (timeit) только doing_performance_analysis составляет True (см. код psuedo ниже).

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)  

5 ответов


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

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() вложенная функция в первом примере и закрытая функция dec и condition параметры здесь хранятся в качестве аргументов экземпляра до тех пор, пока не будет применен декоратор.

декоратор-это просто функция, применяемая к другой функции. Вы можете применить его вручную:

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

if doing_performance_analysis:
    foo = timeit(foo)

как насчет:

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():
   ...

ответ 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 регистрирует ваш вызов в базу данных, файл журнала или что-то еще и эту конфигурацию.get ('RUN_TIMED_FUNCTIONS') проверяет вашу глобальную конфигурацию, а затем добавление декоратора @timed в функцию будет проверять один раз при загрузке, чтобы увидеть, если вы синхронизируете на этом сервере, среде и т. д. а если нет, то это не изменит выполнение функции на производстве или в других средах, где вы заботитесь о производительности.


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()