2012-05-23 5 views
15

Возможно ли украсить функцию условно. Например, я хочу украсить функцию foo() функцией таймера (timeit) только do_performance_analysis - True (см. Ниже приведенный ниже код).Как сделать условный декоратор в python 2.6

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) 

ответ

20

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

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) 

Теперь вы можете использовать его как это:

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

Спасибо! Раздел комментариев не форматируется, поэтому я добавил образец кода к исходному ответу. Можете ли вы объяснить, почему функция синхронизации не называется? – cfpete

+0

Декоратор применяется во время импорта, поэтому переменные экземпляра в настоящее время не консультируются. Вам нужно будет написать для этого другой декоратор, который проверяет себя при вызове. Вне области для этого формата Q и комментариев. :-) –

+0

Как использовать его, если я хочу использовать это на основе классов, то есть на основе Django Class. Там мы должны использовать 'method_decorator'. Как сделать этот код совместимым с этим? – PythonEnthusiast

4

Как насчет:

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

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

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

if doing_performance_analysis: 
    foo = timeit(foo) 
0

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

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