你可以直接执行这个模块进行测试,如果完全没有 输出则表示通过。你也可以找到几个以_test开头的函数,所有的测试用例都包含在这几个函数中。使用方法参见模块文档和测试用例。
# -*- coding: UTF-8 -*-
'''
@summary: 验证器
该模块提供了一个装饰器用于验证参数是否合法,使用方法为:
from validator import validParam, nullOk, multiType
@validParam(i=int)
def foo(i):
return i+1
编写验证器:
1. 仅验证类型:
@validParam(type, ...)
例如:
检查第一个位置的参数是否为int类型:
@validParam(int)
检查名为x的参数是否为int类型:
@validParam(x=int)
验证多个参数:
@validParam(int, int)
指定参数名验证:
@validParam(int, s=str)
针对*和**参数编写的验证器将验证这些参数实际包含的每个元素:
@validParam(varargs=int)
def foo(*varargs): pass
@validParam(kws=int)
def foo7(s, **kws): pass
2. 带有条件的验证:
@validParam((type, condition), ...)
其中,condition是一个表达式字符串,使用x引用待验证的对象;
根据bool(表达式的值)判断是否通过验证,若计算表达式时抛出异常,视为失败。
例如:
验证一个10到20之间的整数:
@validParam(i=(int, '10 20'), nullOk(str, '/^\d+$/')))
5. 如果有更复杂的验证需求,还可以编写一个函数作为验证函数传入。
这个函数接收待验证的对象作为参数,根据bool(返回值)判断是否通过验证,抛出异常视为失败。
例如:
def validFunction(x):
return isinstance(x, int) and x>0
@validParam(i=validFunction)
def foo(i): pass
这个验证函数等价于:
@validParam(i=(int, 'x>0'))
def foo(i): pass
@author: HUXI
@since: 2011-3-22
@change:
'''
import inspect
import re
class ValidateException(Exception): pass
def validParam(*varargs, **keywords):
'''验证参数的装饰器。'''
varargs = map(_toStardardCondition, varargs)
keywords = dict((k, _toStardardCondition(keywords[k]))
for k in keywords)
def generator(func):
args, varargname, kwname = inspect.getargspec(func)[:3]
dctValidator = _getcallargs(args, varargname, kwname,
varargs, keywords)
def wrapper(*callvarargs, **callkeywords):
dctCallArgs = _getcallargs(args, varargname, kwname,
callvarargs, callkeywords)
k, item = None, None
try:
for k in dctValidator:
if k == varargname:
for item in dctCallArgs[k]:
assert dctValidator[k](item)
elif k == kwname:
for item in dctCallArgs[k].values():
assert dctValidator[k](item)
else:
item = dctCallArgs[k]
assert dctValidator[k](item)
except:
raise ValidateException,\
('%s() parameter validation fails, param: %s, value: %s(%s)'
% (func.func_name, k, item, item.__class__.__name__))
return func(*callvarargs, **callkeywords)
wrapper = _wrapps(wrapper, func)
return wrapper
return generator
def _toStardardCondition(condition):
'''将各种格式的检查条件转换为检查函数'''
if inspect.isclass(condition):
return lambda x: isinstance(x, condition)
if isinstance(condition, (tuple, list)):
cls, condition = condition[:2]
if condition is None:
return _toStardardCondition(cls)
if cls in (str, unicode) and condition[0] == condition[-1] == '/':
return lambda x: (isinstance(x, cls)
and re.match(condition[1:-1], x) is not None)
return lambda x: isinstance(x, cls) and eval(condition)
return condition
def nullOk(cls, condition=None):
'''这个函数指定的检查条件可以接受None值'''
return lambda x: x is None or _toStardardCondition((cls, condition))(x)
def multiType(*conditions):
'''这个函数指定的检查条件只需要有一个通过'''
lstValidator = map(_toStardardCondition, conditions)
def validate(x):
for v in lstValidator:
if v(x):
return True
return validate
def _getcallargs(args, varargname, kwname, varargs, keywords):
'''获取调用时的各参数名-值的字典'''
dctArgs = {}
varargs = tuple(varargs)
keywords = dict(keywords)
argcount = len(args)
varcount = len(varargs)
callvarargs = None
if argcount 20'), nullOk(str, '/^\d+$/')))
def foo2(s): pass
_unittest(foo2,
(False, 1),
(False, 'a'),
(True, None),
(False, 1.1),
(True, 21),
(True, '21'))
def _main():
d = globals()
from types import FunctionType
print
for f in d:
if f.startswith('_test'):
f = d[f]
if isinstance(f, FunctionType):
f()
if __name__ == '__main__':
_main()
查看更多关于Python装饰器使用实例:验证参数合法性的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did91182