国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python裝飾器使用實例:驗證參數(shù)合法性

2020-02-23 01:37:26
字體:
供稿:網(wǎng)友

python是不帶靜態(tài)檢查的動態(tài)語言,有時候需要在調(diào)用函數(shù)時保證參數(shù)合法。檢查參數(shù)合法性是一個顯著的切面場景,各個函數(shù)都可能有這個需求。但另一方面,參數(shù)合法性是不是應該由調(diào)用方來保證比較好也是一個需要結(jié)合實際才能回答的問題,總之雙方約定好,不要都不檢查或者都檢查就可以了。下面這個模塊用于在函數(shù)上使用裝飾器進行參數(shù)的合法性驗證。

你可以直接執(zhí)行這個模塊進行測試,如果完全沒有輸出則表示通過。你也可以找到幾個以_test開頭的函數(shù),所有的測試用例都包含在這幾個函數(shù)中。使用方法參見模塊文檔和測試用例。

# -*- coding: UTF-8 -*- '''@summary: 驗證器該模塊提供了一個裝飾器用于驗證參數(shù)是否合法,使用方法為: from validator import validParam, nullOk, multiType @validParam(i=int)def foo(i):  return i+1 編寫驗證器: 1. 僅驗證類型:@validParam(type, ...)例如:檢查第一個位置的參數(shù)是否為int類型:@validParam(int)檢查名為x的參數(shù)是否為int類型:@validParam(x=int) 驗證多個參數(shù):@validParam(int, int)指定參數(shù)名驗證:@validParam(int, s=str) 針對*和**參數(shù)編寫的驗證器將驗證這些參數(shù)實際包含的每個元素:@validParam(varargs=int)def foo(*varargs): pass @validParam(kws=int)def foo7(s, **kws): pass 2. 帶有條件的驗證:@validParam((type, condition), ...)其中,condition是一個表達式字符串,使用x引用待驗證的對象;根據(jù)bool(表達式的值)判斷是否通過驗證,若計算表達式時拋出異常,視為失敗。例如:驗證一個10到20之間的整數(shù):@validParam(i=(int, '10<x<20'))驗證一個長度小于20的字符串:@validParam(s=(str, 'len(x)<20'))驗證一個年齡小于20的學生:@validParam(stu=(Student, 'x.age<20')) 另外,如果類型是字符串,condition還可以使用斜杠開頭和結(jié)尾表示正則表達式匹配。驗證一個由數(shù)字組成的字符串:@validParam(s=(str, '/^/d*$/')) 3. 以上驗證方式默認為當值是None時驗證失敗。如果None是合法的參數(shù),可以使用nullOk()。nullOk()接受一個驗證條件作為參數(shù)。例如:@validParam(i=nullOk(int))@validParam(i=nullOk((int, '10<x<20')))也可以簡寫為:@validParam(i=nullOk(int, '10<x<20')) 4. 如果參數(shù)有多個合法的類型,可以使用multiType()。multiType()可接受多個參數(shù),每個參數(shù)都是一個驗證條件。例如:@validParam(s=multiType(int, str))@validParam(s=multiType((int, 'x>20'), nullOk(str, '/^/d+$/'))) 5. 如果有更復雜的驗證需求,還可以編寫一個函數(shù)作為驗證函數(shù)傳入。這個函數(shù)接收待驗證的對象作為參數(shù),根據(jù)bool(返回值)判斷是否通過驗證,拋出異常視為失敗。例如:def validFunction(x):  return isinstance(x, int) and x>0@validParam(i=validFunction)def foo(i): pass 這個驗證函數(shù)等價于:@validParam(i=(int, 'x>0'))def foo(i): pass  @author: HUXI@since: 2011-3-22@change: ''' import inspectimport re class ValidateException(Exception): pass  def validParam(*varargs, **keywords):  '''驗證參數(shù)的裝飾器。'''     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):  '''將各種格式的檢查條件轉(zhuǎn)換為檢查函數(shù)'''     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):  '''這個函數(shù)指定的檢查條件可以接受None值'''     return lambda x: x is None or _toStardardCondition((cls, condition))(x)  def multiType(*conditions):  '''這個函數(shù)指定的檢查條件只需要有一個通過'''     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):  '''獲取調(diào)用時的各參數(shù)名-值的字典'''     dctArgs = {}  varargs = tuple(varargs)  keywords = dict(keywords)     argcount = len(args)  varcount = len(varargs)  callvarargs = None     if argcount <= varcount:    for n, argname in enumerate(args):      dctArgs[argname] = varargs[n]         callvarargs = varargs[-(varcount-argcount):]     else:    for n, var in enumerate(varargs):      dctArgs[args[n]] = var         for argname in args[-(argcount-varcount):]:      if argname in keywords:        dctArgs[argname] = keywords.pop(argname)         callvarargs = ()     if varargname is not None:    dctArgs[varargname] = callvarargs     if kwname is not None:    dctArgs[kwname] = keywords     dctArgs.update(keywords)  return dctArgs  def _wrapps(wrapper, wrapped):  '''復制元數(shù)據(jù)'''     for attr in ('__module__', '__name__', '__doc__'):    setattr(wrapper, attr, getattr(wrapped, attr))  for attr in ('__dict__',):    getattr(wrapper, attr).update(getattr(wrapped, attr, {}))     return wrapper  #===============================================================================# 測試#===============================================================================  def _unittest(func, *cases):  for case in cases:    _functest(func, *case)    def _functest(func, isCkPass, *args, **kws):  if isCkPass:    func(*args, **kws)  else:    try:      func(*args, **kws)      assert False    except ValidateException:      pass def _test1_simple():  #檢查第一個位置的參數(shù)是否為int類型:  @validParam(int)  def foo1(i): pass  _unittest(foo1,        (True, 1),        (False, 's'),        (False, None))   #檢查名為x的參數(shù)是否為int類型:  @validParam(x=int)  def foo2(s, x): pass  _unittest(foo2,        (True, 1, 2),        (False, 's', 's'))     #驗證多個參數(shù):  @validParam(int, int)  def foo3(s, x): pass  _unittest(foo3,        (True, 1, 2),        (False, 's', 2))     #指定參數(shù)名驗證:  @validParam(int, s=str)  def foo4(i, s): pass  _unittest(foo4,        (True, 1, 'a'),        (False, 's', 1))     #針對*和**參數(shù)編寫的驗證器將驗證這些參數(shù)包含的每個元素:  @validParam(varargs=int)  def foo5(*varargs): pass  _unittest(foo5,       (True, 1, 2, 3, 4, 5),       (False, 'a', 1))     @validParam(kws=int)  def foo6(**kws): pass  _functest(foo6, True, a=1, b=2)  _functest(foo6, False, a='a', b=2)     @validParam(kws=int)  def foo7(s, **kws): pass  _functest(foo7, True, s='a', a=1, b=2)  def _test2_condition():  #驗證一個10到20之間的整數(shù):  @validParam(i=(int, '10<x<20'))  def foo1(x, i): pass  _unittest(foo1,        (True, 1, 11),        (False, 1, 'a'),        (False, 1, 1))     #驗證一個長度小于20的字符串:  @validParam(s=(str, 'len(x)<20'))  def foo2(a, s): pass  _unittest(foo2,        (True, 1, 'a'),        (False, 1, 1),        (False, 1, 'a'*20))     #驗證一個年齡小于20的學生:  class Student(object):    def __init__(self, age): self.age=age     @validParam(stu=(Student, 'x.age<20'))  def foo3(stu): pass  _unittest(foo3,        (True, Student(18)),        (False, 1),        (False, Student(20)))     #驗證一個由數(shù)字組成的字符串:  @validParam(s=(str, r'/^/d*$/'))  def foo4(s): pass  _unittest(foo4,        (True, '1234'),        (False, 1),        (False, 'a1234'))  def _test3_nullok():  @validParam(i=nullOk(int))  def foo1(i): pass  _unittest(foo1,        (True, 1),        (False, 'a'),        (True, None))     @validParam(i=nullOk(int, '10<x<20'))  def foo2(i): pass  _unittest(foo2,        (True, 11),        (False, 'a'),        (True, None),        (False, 1))  def _test4_multitype():  @validParam(s=multiType(int, str))  def foo1(s): pass  _unittest(foo1,        (True, 1),       (True, 'a'),       (False, None),       (False, 1.1))     @validParam(s=multiType((int, 'x>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()            
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 济南市| 永嘉县| 会昌县| 武胜县| 清流县| 益阳市| 霞浦县| 鄂托克前旗| 奉贤区| 鄢陵县| 乌恰县| 逊克县| 连平县| 宁陵县| 通辽市| 巨野县| 杨浦区| 台中县| 宝应县| 三河市| 轮台县| 义马市| 青龙| 宝坻区| 准格尔旗| 钟祥市| 师宗县| 清流县| 梁山县| 青神县| 黄浦区| 东莞市| 噶尔县| 千阳县| 色达县| 界首市| 瑞丽市| 宜兴市| 六枝特区| 海晏县| 涟水县|