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

如何在Python运行时强制校验组合(参数化泛型)类型提示?

Python中强制校验参数化泛型类型提示的实现方案

可以实现对list[int]这类参数化泛型的类型校验,下面是几种可行的解决方案:

方案1:使用beartype库(推荐,轻量原生支持)

beartype是专注于运行时类型校验的库,原生支持参数化泛型的校验逻辑,用法简洁直接:

from beartype import beartype

@beartype
def my_fn(a: list[int]) -> None:
    pass

my_fn(a=[1, 2])   # 正常执行
my_fn(a=[1, '2']) # 抛出BeartypeCallHintParamViolation异常,符合预期

方案2:使用pydantic的参数校验装饰器

如果项目已经在用pydantic做数据验证,直接用它的validate_arguments装饰器即可实现泛型校验:

from pydantic import validate_arguments

@validate_arguments
def my_fn(a: list[int]) -> None:
    pass

my_fn(a=[1, 2])   # 正常执行
my_fn(a=[1, '2']) # 抛出ValidationError异常,明确提示元素类型错误

方案3:手动实现泛型校验(无第三方依赖)

如果不想引入第三方库,可以基于Python的typing模块解析类型提示,自己实现校验逻辑:

针对list[int]的简易版本

def enforce_list_int(func):
    def wrapper(*args, **kwargs):
        a = kwargs.get('a', args[0] if args else None)
        # 先校验外层list类型
        if not isinstance(a, list):
            raise TypeError(f"参数a必须是list类型,实际为{type(a)}")
        # 校验每个元素的int类型
        for idx, item in enumerate(a):
            if not isinstance(item, int):
                raise TypeError(f"列表a第{idx}个元素类型错误:预期int,实际为{type(item)}")
        return func(*args, **kwargs)
    return wrapper

@enforce_list_int
def my_fn(a: list[int]) -> None:
    pass

my_fn(a=[1, 2])   # 正常执行
my_fn(a=[1, '2']) # 抛出TypeError,符合预期

通用泛型校验版本(支持更多泛型类型)

如果需要支持dict[str, int]、tuple[int, str]等更多泛型,可以用typing.get_origin和typing.get_args解析类型提示:

import inspect
from typing import get_args, get_origin

def enforce_generic_types(func):
    sig = inspect.signature(func)
    param_annotations = {name: param.annotation for name, param in sig.parameters.items()}

    def wrapper(*args, **kwargs):
        bound_args = sig.bind(*args, **kwargs).arguments
        for param_name, param_value in bound_args.items():
            anno = param_annotations[param_name]
            origin_type = get_origin(anno)
            # 判断是否是参数化泛型
            if origin_type is None:
                continue
            
            # 处理list类型
            if origin_type is list:
                if not isinstance(param_value, list):
                    raise TypeError(f"参数{param_name}必须是{anno}类型,实际为{type(param_value)}")
                inner_type = get_args(anno)[0]
                for idx, item in enumerate(param_value):
                    if not isinstance(item, inner_type):
                        raise TypeError(f"{param_name}第{idx}个元素类型错误:预期{inner_type},实际为{type(item)}")
            # 扩展处理dict类型
            elif origin_type is dict:
                key_type, val_type = get_args(anno)
                if not isinstance(param_value, dict):
                    raise TypeError(f"参数{param_name}必须是{anno}类型,实际为{type(param_value)}")
                for k, v in param_value.items():
                    if not isinstance(k, key_type) or not isinstance(v, val_type):
                        raise TypeError(f"{param_name}中键值对({k}:{v})类型错误:预期键{key_type}、值{val_type}")
        return func(*args, **kwargs)
    return wrapper

@enforce_generic_types
def my_fn(a: list[int]) -> None:
    pass

@enforce_generic_types
def my_dict_fn(b: dict[str, int]) -> None:
    pass

my_fn(a=[1, 2])          # 正常执行
my_fn(a=[1, '2'])        # 抛出TypeError
my_dict_fn(b={"age": 20}) # 正常执行
my_dict_fn(b={"age": "20"}) # 抛出TypeError

补充说明

你之前尝试的type_enforced库对参数化泛型的支持有限,因此无法实现预期效果,上面的三种方案都能满足你的需求,其中beartype和pydantic是成熟的第三方库,推荐优先使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 08:38:49