对函数部分或全部参数进行类型检查

Posted 千翻娃儿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对函数部分或全部参数进行类型检查相关的知识,希望对你有一定的参考价值。

对函数部分或全部参数进行类型检查

构建一个装饰器,通过对装饰器中传入类型参数,来对装饰的函数的对应参数进行类型检查。

from inspect import signature
from functools import wraps

def typeassert(*tyargs,**tykwargs):
    def decorator(func):
        #获取指定的强制类型参数
        sig=signature(func)
        required_types=sig.bind_partial(*tyargs,**tykwargs).arguments#OrderedDict类型,可以只对前面的参数进行in搜索判定,可以把前面的参数当作key来获取对应的类型

        @wraps(func)
        def wrapper(*args,**kwargs):
            #获取函数输入的各参数类型
            input_vals=sig.bind(*args,**kwargs)

            #对输入的每个参数,如果出现在设定的类型检查中,则进行类型检查
            for name,value in input_vals.arguments.items():
                if name in required_types:
                    if not isinstance(value,required_types[name]):
                        raise TypeError(
                            \'Argument {} must be {}\'.format(name, required_types[name])
                            )
            return func(*args,**kwargs)
        return wrapper
    return decorator

@typeassert(str,z=int)#第一个位置参数为str,z必须为int
def func(x,y,z):
    return y+z

>>>print(func(1,2,3))
TypeError: Argument x must be <class \'str\'>
    
@typeassert(int,y=str,z=int)#第一个位置参数为int,y为str,z必须为int
def func(x,y,z):
    print(x,y,z)
>>>func1(3,\'s\',1)
3 s 1
>>>func1(\'hhh\',\'s\',1)
TypeError: Argument x must be <class \'int\'>

另外也可以通过函数注解来实现,之前实现过,代码如下:

def para_check(func):#外函数,传入的参数是待检验函数对象本身
    sig=inspect.signature(func)#获取函数参数签名
    parameters=sig.parameters#获取参数的有序字典
    arg_names=tuple(parameters.keys())#获取参数的名称
    def wrapper(*args,**kwargs):#内函数
        check_list=[]#待检验的参数对
        for i,val in enumerate(args):#检验所有的位置参数
            arg_name=arg_names[i]
            anno=parameters[arg_name].annotation#该参数期待的类型
            check_list.append((arg_name,anno,val))
        for arg_name,val in kwargs.items():#检验所有的关键字参数
            anno=parameters[arg_name].annotation
            check_list.append((arg_name,anno,val))

        for check_arg in check_list:#逐个参数检验
            if not isinstance(check_arg[2],check_arg[1]):
                raise TypeError(\'the input %s expect type %s,but got %s\'%(check_arg[0],check_arg[1],type(check_arg[2])))
        return func(*args,**kwargs)
    return wrapper

@para_check
def test(x: int, y: int):
    return x + y
>>>print(test(1,2))
3
>>>print(test(1,\'3\'))
TypeError: the input y expect type <class \'int\'>,but got <class \'str\'>

后者不需要使用传参数的装饰器。但是明显前者更灵活,用前者进行类型检查,那么后面的函数注解就可以做其它事情而非类型检查了。

以上是关于对函数部分或全部参数进行类型检查的主要内容,如果未能解决你的问题,请参考以下文章

为啥要使用 toString() 对可以使用 typeof 进行检查的参数进行类型检查?

深入理解函数模板

如何通过Dreamweaver批量对整个站点或目录进行代码搜索或部分全部替换

Python类型注解

如何对媒体片段的任何部分进行范围请求?

何时在启用可空引用类型的情况下对参数进行空检查