pyextend库-accepts函数参数检查
accepts(exception=TypeError, **types)
参数:
exception: 检查失败时的抛出异常类型
**types: 待检查的k-v参数
**types参数支持
a=int : 待测函数参数a必须为 int 类型, 否则检查失败
b='__iter__' : 待测参数 b 必须为 实现 __iter__ 函数的 iterable类型
c=('__iter__', None) : 待测参数 c 必须为实现 __iter__函数的 iterable类型或者None.
范例:
Example 1: @accepts(a=int, b='__iter__', c=str) def test(a, b=None, c=None): print('accepts OK') test(13, b=[], c='abc') -- OK test('aaa', b=(), c='abc') --Failed Example 2: @accepts(a=int, b=('__iter__', None), c=str) def test(a, b=None, c=None): print('accepts OK') test(13, b=[], c='abc') -- OK test(13, b=None, c='abc') -- OK
代码:
def accepts(exception=TypeError, **types): """ A wrapper of function for checking function parameters type """ def check_param(v, type_or_funcname): if isinstance(type_or_funcname, tuple): results1 = [check_param(v, t) for t in type_or_funcname if t is not None] results2 = [v == t for t in type_or_funcname if t is None] return any(results1) or any(results2) is_type_instance, is_func_like = False, False try: is_type_instance = isinstance(v, type_or_funcname) except TypeError: pass if isinstance(type_or_funcname, str): is_func_like = hasattr(v, type_or_funcname) return is_type_instance or is_func_like def check_accepts(f): assert len(types) <= f.__code__.co_argcount,\ 'accept number of arguments not equal with function number of arguments in "{}"'.format(f.__name__) @functools.wraps(f) def new_f(*args, **kwargs): for i, v in enumerate(args): if f.__code__.co_varnames[i] in types and \ not check_param(v, types[f.__code__.co_varnames[i]]): raise exception("function '%s' arg '%s'=%r does not match %s" % (f.__name__, f.__code__.co_varnames[i], v, types[f.__code__.co_varnames[i]])) del types[f.__code__.co_varnames[i]] for k, v in kwargs.items(): if k in types and \ not check_param(v, types[k]): raise exception("function '%s' arg '%s'=%r does not match %s" % (f.__name__, k, v, types[k])) return f(*args, **kwargs) return new_f return check_accepts