Как сделать условный декоратор в python 2.6
Возможно ли, чтобы декоратор выполнял функцию условно. Например, я хочу украсить функцию foo()
функцией таймера (timeit
), только make_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)
Ответы
Ответ 1
Декораторы - это просто вызывающие элементы, которые возвращают замену, необязательно одну и ту же функцию, обертку или что-то совершенно другое. Таким образом, вы можете создать условный декоратор:
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)
Ответ 2
Декоратор - это просто функция, применяемая к другой функции. Вы можете применить его вручную:
def foo():
# whatever
time.sleep(2)
if doing_performance_analysis:
foo = timeit(foo)
Ответ 3
Как насчет:
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():
...
Ответ 4
Ответ на Blckkngh отлично, если вы хотите делать проверку каждый раз, когда вы вызываете эту функцию, но если у вас есть параметр, который вы можете читать один раз и никогда не изменяетесь, вы можете не захотеть проверять этот параметр каждый раз, когда вызывается функция украшений, В некоторых из наших высокопроизводительных демонов на работе я написал декоратор, который проверяет файл настроек один раз, когда первый файл 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 к функции будет проверяться один раз при загрузке, чтобы узнать, это время на этом сервере, среда и т.д., а если нет, то это не изменит выполнение функции на производстве или в других средах, в которых вы заботитесь о производительности.
Ответ 5
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()