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)