如何在python中使用条件装饰器
是否可以有条件地装饰函数。例如,我想用一个计时器函数(如何在python中使用条件装饰器,python,conditional,decorator,python-decorators,Python,Conditional,Decorator,Python Decorators,是否可以有条件地装饰函数。例如,我想用一个计时器函数(timeit)来修饰函数foo()),只做性能分析是正确的(参见下面的psuedo代码) 那么: def foo(): ... if doing_performance_analysis: foo = timeit(foo) 我想您甚至可以将其包装到一个装饰器中,该装饰器将接受一个布尔标志和另一个装饰器,并且仅在标志设置为True时应用后者: def cond_decorator(flag, dec): def deco
timeit
)来修饰函数foo()
),只做性能分析是正确的(参见下面的psuedo代码)
那么:
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():
...
装饰器只是应用于另一个函数的函数。您可以手动应用它:
def foo():
# whatever
time.sleep(2)
if doing_performance_analysis:
foo = timeit(foo)
decorator只是返回替换的可调用函数,可以选择相同的函数、包装器或完全不同的东西。因此,您可以创建条件装饰器:
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)
在这里,\uuuu call\uu
方法与第一个示例中返回的decorator()
嵌套函数的作用相同,在应用decorator之前,这里的closed-overdec
和condition
参数将作为实例上的参数存储。Blckknght的答案非常好,如果您想在每次调用函数时进行检查,但是,如果您有一个可以读取一次且从不更改的设置,那么您可能不希望在每次调用修饰函数时都检查该设置。在我们工作的一些高性能守护进程中,我编写了一个decorator,它在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 decorator添加到函数将在加载时检查一次,以查看您是否在此服务器、环境上计时,如果没有,则不会改变生产环境或其他您关心性能的环境中功能的执行。以下是对我有效的方法:
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()
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})
谢谢评论部分没有格式化,所以我在原始回复中添加了示例代码。你能解释一下为什么不调用定时函数吗?decorator是在导入时应用的,所以当时没有参考实例变量。你必须为此编写一个不同的装饰器,一个在调用时检查self的装饰器。超出此Q和注释格式的范围。:-)如果我想在基于类的方法(即Django基于类的视图)上使用它,我将如何使用它。在那里,我们必须使用方法\u decorator
。如何使此代码与之兼容?@pythonenthsusiast:只需传入调用结果:@method\u decorator(conditional\u decorator(timeit,doing\u performance\u analysis))
。
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})