python对函数参数添加强制类型校验

python函数参数强制类型校验

import inspect
def type_validate(func):
    def inner(*args, **kwargs):
        full_args_spec = inspect.getfullargspec(func)
        if args:
            new_func_args = full_args_spec.args
            if len(full_args_spec.args) != len(full_args_spec.annotations.keys()):
                args = args[1:]
                new_func_args = full_args_spec.args[1:]
            for i, v in enumerate(args):
                if not isinstance(v, full_args_spec.annotations[new_func_args[i]]):
                    raise TypeError(f"{v}不是{full_args_spec.annotations[new_func_args[i]]}")
        if kwargs:
            for k, v in kwargs.items():
                if not isinstance(v, full_args_spec.annotations[k]):
                    raise TypeError(f"{v}不是{full_args_spec.annotations[k]}")
        func(*args, **kwargs)

    return inner

测试效果如下
支持对实例函数装饰

@type_validate
def f(a: int, b: int):
    ...

f(1, "2")

Traceback (most recent call last):
  File "D:\pythonProject\node_run\demo.py", line 28, in <module>
    f(1, "2")
  File "D:\pythonProject\node_run\demo.py", line 15, in inner
    raise TypeError(f"{v}不是{full_args_spec.annotations[new_func_args[i]]}")
TypeError: 2不是<class 'int'>

升级版 强制类型校验的同时限定参数取值

def type_value_validate(*ags, **kags):
    def type_validate(func):
        def inner(*args, **kwargs):
            full_args_spec = inspect.getfullargspec(func)
            if args and len(args) != 1:  # 排除self
                new_func_args = full_args_spec.args
                if len(full_args_spec.args) != len(full_args_spec.annotations.keys()):
                    args = args[1:]
                    new_func_args = full_args_spec.args[1:]
                for i, v in enumerate(args):
                    if not isinstance(v, full_args_spec.annotations[new_func_args[i]]):
                        raise TypeError(f"{v}不是{full_args_spec.annotations[new_func_args[i]]}类型")

                    if ags:
                        if isinstance(ags[i], list):
                            if any([not isinstance(j, full_args_spec.annotations[new_func_args[i]]) for j in ags[i]]):
                                raise ValueError(f"{ags[i]}中值不符合{full_args_spec.annotations[new_func_args[i]]}定义")
                            if v not in ags[i]:
                                raise ValueError(f"{v}不在{ags[i]}中")
                        if isinstance(ags[i], dict):
                            if list_values := ags[i].get("list"):
                                if any([not isinstance(j, full_args_spec.annotations[new_func_args[i]]) for j in
                                        list_values]):
                                    raise ValueError(
                                        f"{list_values}中值不符合{full_args_spec.annotations[new_func_args[i]]}定义")
                                if v not in list_values:
                                    raise ValueError(f"{v}不在{list_values}中")
                            if pattern := ags[i].get("pattern"):
                                if not re.match(pattern, v):
                                    raise ValueError(f"{v}不匹配{pattern}")

                if kags:
                    for k, v in kags.items():
                        if isinstance(v, list):
                            if any([not isinstance(j, full_args_spec.annotations[k]) for j in v]):
                                raise ValueError(
                                    f"{v}中值不符合{full_args_spec.annotations[k]}定义")
                            if args[full_args_spec.args.index(k)] not in v:
                                raise ValueError(f"{args[full_args_spec.args.index(k)]}不在{v}中")
                        if isinstance(v, dict):
                            if list_values := v.get("list"):
                                if any([not isinstance(j, full_args_spec.annotations[k]) for j in
                                        list_values]):
                                    raise ValueError(f"{list_values}中值不符合{full_args_spec.annotations[k]}定义")
                                if args[full_args_spec.args.index(k)] not in list_values:
                                    raise ValueError(f"{args[full_args_spec.args.index(k)]}不在{list_values}中")
                            if pattern := v.get("pattern"):
                                if not re.match(pattern, args[full_args_spec.args.index(k)]):
                                    raise ValueError(f"{args[full_args_spec.args.index(k)]}不匹配{pattern}")

            if kwargs:
                idx = 0
                for k, v in kwargs.items():
                    if not isinstance(v, full_args_spec.annotations[k]):
                        raise TypeError(f"{v}不是{full_args_spec.annotations[k]}")
                    if ags:
                        if idx == len(ags):
                            continue
                        if isinstance(ags[idx], list):
                            if any([not isinstance(i, full_args_spec.annotations[k]) for i in ags[idx]]):
                                raise ValueError(f"{ags[idx]}中值不符合{full_args_spec.annotations[k]}定义")
                            if v not in ags[idx]:
                                raise ValueError(f"{v}不在{ags[idx]}中")
                        if isinstance(ags[idx], dict):
                            if list_values := ags[idx].get("list"):
                                if any([not isinstance(i, full_args_spec.annotations[k]) for i in list_values]):
                                    raise ValueError(f"{list_values}中值不符合{full_args_spec.annotations[k]}定义")
                                if v not in list_values:
                                    raise ValueError(f"{v}不在{list_values}中")
                            if pattern := ags[idx].get("pattern"):
                                if not re.match(pattern, v):
                                    raise ValueError(f"{v}不匹配{pattern}")
                        idx += 1
                    if kags:
                        if not kags.get(k):
                            continue
                        if isinstance(kags[k], list):
                            if any([not isinstance(i, full_args_spec.annotations[k]) for i in kags[k]]):
                                raise ValueError(f"{kags[k]}中值不符合{full_args_spec.annotations[k]}定义")
                            if v not in kags[k]:
                                raise ValueError(f"{v}不在{kags[k]}中")
                        if isinstance(kags[k], dict):
                            if list_values := kags[k].get("list"):
                                if any([not isinstance(i, full_args_spec.annotations[k]) for i in
                                        list_values]):
                                    raise ValueError(f"{list_values}中值不符合{full_args_spec.annotations[k]}定义")
                                if v not in list_values:
                                    raise ValueError(f"{v}不在{list_values}中")
                            if pattern := kags[k].get("pattern"):
                                if not re.match(pattern, v):
                                    raise ValueError(f"{v}不匹配{pattern}")
            func(*args, **kwargs)
        return inner
    return type_validate

测试效果如下

@value_type_validate([1, 2], {"pattern": "/.*/.*"})
def demo(a: int, b: str):
    print(a, b)


demo(a=1, b="2")

Traceback (most recent call last):
  File "D:\pythonProject\node_run\demo.py", line 105, in <module>
    demo(a=1, b="2")
  File "D:\pythonProject\node_run\demo.py", line 76, in inner
    raise ValueError(f"{v}不匹配{pattern}")
ValueError: 2不匹配/.*/.*

目前支持如下格式使用(仅支持list校验和正则校验)

@value_type_validate({"list": [1, 2]}, {"pattern": "/.*/.*"})
def demo(a: int, b: str):
    print(a, b)

@value_type_validate(a={"list": [1, 2]}, b={"pattern": "/.*/.*"})
def demo(a: int, b: str):
    print(a, b)

@value_type_validate(a=[1, 2], b={"pattern": "/.*/.*"})
def demo(a: int, b: str):
    print(a, b)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值