我想根据范围验证类成员的输入值。我正在尝试装饰器模块,因为它提供了所有好处(例如保留类元数据)。
这是我的验证装饰者:
from decorator import decorator
@decorator
def valid_range(f,*args,**kwargs):
value = args[1]
inrange = True
try:
inrange = (inrange and (value <= range['max_inclusive']))
except KeyError: pass
try:
inrange = (inrange and (value < range['max_exclusive']))
except KeyError: pass
try:
inrange = (inrange and (value >= range['min_inclusive']))
except KeyError: pass
try:
inrange = (inrange and (value > range['min_exclusive']))
except KeyError: pass
if inrange:
return f(*args,**kwargs)
else:
raise Exception
以下是装饰器的应用(假设value_setter
在某个类的主体中):
@valid_range({'max_inclusive':1,'min_inclusive':0})
def value_setter(self,value):
self.value = value
有没有办法将max / min dict
作为参数传递给我的装饰器(在装饰器定义本身中用作range
)?我知道如何使用常规装饰器来做到这一点,但正如我所说,我想尽可能使用装饰器模块。
如果不可能,我还能怎样做并保留所有识别数据?我应该考虑使用任何替代模块吗?
编辑:请注意,将range
dict
参数作为*args
和**kwargs
的一部分传递不是一种选择。我不想将它作为我的类定义的一部分。
答案 0 :(得分:4)
你可以写自己的(缩短的例子):
from functools import wraps
def valid_range(min_val=0, max_val=0):
def deco(f):
@wraps(f)
def wrapper(*args, **kwargs):
val = args[0]
if min_val <= val <= max_val:
return f(*args, **kwargs):
else:
raise RangeError
return wrapper
return deco
用法:
@valid_range(10, 20)
def f(x):
pass
答案 1 :(得分:0)
提出以下解决方案。基本上,我将装饰器包装在另一个装饰器中。
这确实允许将max和min的条目与其余代码分开,但它绝对不是一个好的解决方案而忽略了decorator
模块的要点(这是为了简化应用程序)装饰者)。出于这个原因,我更喜欢acushner对我自己的回答。
from decorator import decorator
@decorator
def _valid_range(f,*args,**kwargs):
return f(*args,range = {'max_inclusive':1,'min_inclusive':0},**kwargs)
@decorator
@_valid_range
def valid_range(f,*args,**kwargs):
range = kwargs.pop('range',None)
value = args[0]
inrange = True
try:
inrange = (inrange and (value <= range['max_inclusive']))
except KeyError: pass
try:
inrange = (inrange and (value < range['max_exclusive']))
except KeyError: pass
try:
inrange = (inrange and (value >= range['min_inclusive']))
except KeyError: pass
try:
inrange = (inrange and (value > range['min_exclusive']))
except KeyError: pass
if inrange:
return f(*args,**kwargs)
else:
raise Exception
@valid_range
def value_setter(value):
print(value)