You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否用Python结构化解包做类型检查?如何实现注解驱动的类型检查装饰器?

解答

一、可以实现基于装饰器+模式匹配的运行时类型检查

当然可以实现你想要的功能,不过需要修正模式匹配的写法,同时完善装饰器的逻辑。以下是可行的实现代码:

首先定义自定义异常:

class BadType(TypeError):
    pass

然后实现装饰器:

def my_checker(func):
    def wrapper(*args, **kwargs):
        # 提取参数注解,排除返回值注解(如果存在)
        param_annotations = func.__annotations__.copy()
        return_annot = param_annotations.pop('return', None)
        
        # 检查位置参数
        for (param_name, annot), arg in zip(param_annotations.items(), args):
            match arg:
                # 用守卫(guard)判断参数是否符合注解类型
                case _ if isinstance(arg, annot):
                    continue
                case _:
                    raise BadType(f"参数 {param_name} 预期类型 {annot.__name__},实际为 {type(arg).__name__}")
        
        # 补充检查关键字参数
        for param_name, arg in kwargs.items():
            if param_name in param_annotations:
                annot = param_annotations[param_name]
                match arg:
                    case _ if isinstance(arg, annot):
                        continue
                    case _:
                        raise BadType(f"参数 {param_name} 预期类型 {annot.__name__},实际为 {type(arg).__name__}")
        
        # 执行原函数
        result = func(*args, **kwargs)
        
        # 可选:检查返回值类型
        if return_annot is not None:
            match result:
                case _ if isinstance(result, return_annot):
                    pass
                case _:
                    raise BadType(f"返回值预期类型 {return_annot.__name__},实际为 {type(result).__name__}")
        
        return result
    return wrapper

使用示例:

@my_checker
def some_func(a: int, b: str) -> bool:
    return b.isdigit()

# 正常调用
some_func(123, "456")  # 返回 True

# 错误调用会抛出BadType
some_func("123", "456")  # 参数 a 预期类型 int,实际为 str

二、模式匹配中使用注解类型的注意点

注解本质是类对象(比如int、str),在模式匹配里直接写case annotation()虽然能匹配该类的实例,但有两个局限:

  1. 会匹配子类实例(比如注解是int时,bool实例也会被匹配,因为bool是int的子类),如果要严格匹配类型,把守卫条件改成type(arg) is annot即可。
  2. 无法处理复杂类型注解(比如list[int]、Union[int, str]),这种情况下用isinstance结合守卫的写法更灵活,也能兼容更多注解场景。

三、现成的第三方库

没必要自己写轮子,已有成熟的第三方库做这件事,最常用的是typeguard:

  • 完全支持PEP 484标准的类型注解,包括各种复杂类型(Union、List、Dict、Optional等)
  • 提供@typeguard.typechecked装饰器,一键给函数加上运行时类型检查
  • 支持配置检查严格度、忽略特定参数等功能

安装:

pip install typeguard

使用示例:

from typeguard import typechecked

@typechecked
def some_func(a: int, b: str) -> bool:
    return b.isdigit()

some_func(123, "456")  # 正常执行
some_func("123", "456")  # 抛出TypeError

另外还有pydantic,它主要用于数据验证,但也能通过@pydantic.validate_arguments装饰器实现类似功能,还支持更复杂的数据结构校验。

内容的提问来源于stack exchange,提问作者user3338584

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 12:55:19