Python3.8环境下如何为装饰器添加传入函数的签名类型校验
Python装饰器装饰阶段签名校验实现
你可以直接使用Python标准库的inspect和typing.get_type_hints实现需求,无需第三方依赖,完全适配Python3.8版本。校验逻辑会在装饰器执行阶段(也就是你打印decorating function...的阶段)直接执行,不通过就抛出明确报错,不会等到函数运行时才校验。
完整实现代码
from dataclasses import dataclass from typing import Callable, get_type_hints from inspect import signature @dataclass class User: name: str @dataclass class Point: x: float y: float z: float def logging_decorator(f: Callable[[User, Point], bool]) -> Callable[[User, Point], bool]: # 签名校验逻辑 sig = signature(f) param_count = len(sig.parameters) # 校验参数数量 if param_count != 2: raise ValueError(f"签名不符合要求:期望2个参数,实际传入{param_count}个参数") hints = get_type_hints(f) # 校验返回值类型 if 'return' not in hints: raise ValueError("签名不符合要求:缺少返回值类型注解,期望返回bool") if hints['return'] is not bool: raise ValueError(f"签名不符合要求:返回值类型期望bool,实际得到{hints['return'].__name__}") # 按顺序校验两个参数的类型 expected_types = [User, Point] param_names = list(sig.parameters.keys()) for idx in range(2): param_name = param_names[idx] expected_type = expected_types[idx] if param_name not in hints: raise ValueError(f"签名不符合要求:第{idx+1}个参数[{param_name}]缺少类型注解,期望{expected_type.__name__}") actual_type = hints[param_name] if actual_type is not expected_type: raise ValueError(f"签名不符合要求:第{idx+1}个参数[{param_name}]类型期望{expected_type.__name__},实际得到{actual_type.__name__}") # 原有逻辑 print('decorating function...') def decorated(a: User, b: Point) -> bool: print(f'User {a.name} calling with points {b.x},{b.y},{b.z}') ret = f(a, b) print(f'returned {ret}') return ret return decorated
测试效果
# 正常装饰,无报错 @logging_decorator def good_f(a: User, b: Point) -> bool: return True # 装饰阶段直接抛出错误:ValueError: 签名不符合要求:返回值类型期望bool,实际得到str @logging_decorator def bad_f(a: str, b: str) -> str: return "Hello"
内容的提问来源于stack exchange,提问作者Blue7
相关产品推荐
相关产品推荐

