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

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

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

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'>

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

1 声望
2 粉丝
0 条评论
推荐阅读
python迭代器与生成器详解
a是一个列表,本身也是一个迭代器(iterator);for循环能够遍历的一定是iterator,在遍历时会默认调用迭代器的iter()方法,将其显示出来,即等价于:

千翻娃儿阅读 1.2k

数据结构与算法:二分查找
一、常见数据结构简单数据结构(必须理解和掌握)有序数据结构:栈、队列、链表。有序数据结构省空间(储存空间小)无序数据结构:集合、字典、散列表,无序数据结构省时间(读取时间快)复杂数据结构树、 堆图二...

白鲸鱼9阅读 5.3k

滚蛋吧,正则表达式!
你是不是也有这样的操作,比如你需要使用「电子邮箱正则表达式」,首先想到的就是直接百度上搜索一个,然后采用 CV 大法神奇地接入到你的代码中?

良许3阅读 1.5k

搭个ChatGPT算法模型,从哪开始?
最近 ChatGPT 很火,火到了各行各业。记得去年更多的还是码农最新体验后拿它搜代码,现在各行各业都进来体验,问它咋理财、怎么写报告和给小孩起名。😂 也因此让小傅哥在头条的一篇关于 ChatGPT 的文章都有了26万...

小傅哥6阅读 1.2k

封面图
【golang】defer详解
特性我们简单的过一下 defer 关键字的基础使用,让大家先有一个基础的认知一、延迟调用 {代码...} 输出结果: {代码...} 二、后进先出 {代码...} 输出结果: {代码...} 三、运行时间点 {代码...} 输出结果: {代...

去去10023阅读 4.1k

程序员适合创业吗?
大家好,我是良许。从去年 12 月开始,我已经在视频号、抖音等主流视频平台上连续更新视频到现在,并得到了不错的评价。每个视频都花了很多时间精力用心制作,欢迎大家关注哦~考虑到有些小伙伴没有看过我的视频,...

良许3阅读 1.3k

Ubuntu20.04 从源代码编译安装 python3.10
Ubuntu 22.04 Release DateUbuntu 22.04 Jammy Jellyfish is scheduled for release on April 21, 2022If you’re ready to use Ubuntu 22.04 Jammy Jellyfish, you can either upgrade your current Ubuntu syste...

ponponon1阅读 4.6k评论 1

1 声望
2 粉丝
宣传栏