pyextend库-accepts函数参数检查

pyextend - python extend lib

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

 

posted @ 2016-02-17 11:23  Vito.K  阅读(1027)  评论(0编辑  收藏  举报