为适配Dataclass的StdVectorList类添加类型提示以约束vec_type
为StdVectorList添加类型提示约束vec_type的解决思路
我实现了一个继承自MutableSequence的Python类StdVectorList,它封装了CERN ROOT的C++ std::vector,支持用Python列表初始化。但类的元素类型是通过初始化参数vec_type(字符串,比如"float")指定的,导致实例的类型信息无法被类型检查工具识别,也无法约束用户传入合法的vec_type值。以下是几种可行的解决思路:
原类初始化代码:
from collections.abc import MutableSequence import ROOT class StdVectorList(MutableSequence): """A python list interface to ROOT's std::vector""" def __init__(self, vec_type, value=[]): """ Args: vec_type: C++ type for the std::vector (eg. "float", "string", etc.) value: list with which to init the vector """ self._vector = ROOT.vector(vec_type)(value) #: C++ type for the std::vector (eg. "float", "string", etc.) self.vec_type = vec_type
方案1:用Literal限定合法的vec_type字符串
直接用typing.Literal列出所有允许的vec_type取值,让类型检查工具(如mypy、Pyright)强制约束用户只能传入指定字符串,同时结合Generic关联对应的Python元素类型,让实例的类型信息可被识别。
修改后的代码:
from collections.abc import MutableSequence from typing import Literal, Generic, TypeVar import ROOT # 定义允许的C++类型字符串集合 AllowedVecType = Literal["float", "int", "string", "double"] # 绑定对应的Python元素类型 T = TypeVar("T", float, int, str, float) class StdVectorList(MutableSequence, Generic[T]): """A python list interface to ROOT's std::vector""" def __init__(self, vec_type: AllowedVecType, value: list[T] = []): """ Args: vec_type: C++ type for the std::vector (eg. "float", "string", etc.) value: list with which to init the vector """ self._vector = ROOT.vector(vec_type)(value) self.vec_type: AllowedVecType = vec_type # 使用示例 a = StdVectorList("float") # 合法,类型检查通过 b = StdVectorList("int") # 合法 # c = StdVectorList("char") # 类型检查工具会报错,提示不在允许范围内
方案2:通过Generic+工厂函数隐藏字符串参数
定义与Python类型绑定的泛型类,用工厂函数自动完成Python类型到C++类型字符串的映射,用户无需手动传入vec_type字符串,实例的类型信息更直观。
修改后的代码:
from collections.abc import MutableSequence from typing import Generic, TypeVar, overload, Literal import ROOT T = TypeVar("T", float, int, str, float) # 建立Python类型到C++类型字符串的映射表 TYPE_MAP = { float: "float", int: "int", str: "string", float: "double" } class StdVectorList(MutableSequence, Generic[T]): """A python list interface to ROOT's std::vector""" def __init__(self, vec_type: str, value: list[T] = []): self._vector = ROOT.vector(vec_type)(value) self.vec_type = vec_type # 重载工厂函数,支持两种调用方式 @overload def create_std_vector(value: list[float] = [], /) -> StdVectorList[float]: ... @overload def create_std_vector(value: list[int] = [], /) -> StdVectorList[int]: ... @overload def create_std_vector(value: list[str] = [], /) -> StdVectorList[str]: ... @overload def create_std_vector(vec_type: Literal["float", "int", "string"], value: list = [], /) -> StdVectorList: ... def create_std_vector(vec_type_or_value=None, value=[]): if isinstance(vec_type_or_value, list): # 从列表元素类型自动推断C++类型 if not vec_type_or_value: raise ValueError("无法从空列表推断元素类型") elem_type = type(vec_type_or_value[0]) vec_type = TYPE_MAP.get(elem_type) if not vec_type: raise TypeError(f"不支持的元素类型: {elem_type}") return StdVectorList(vec_type, vec_type_or_value) elif isinstance(vec_type_or_value, str): return StdVectorList(vec_type_or_value, value) else: raise ValueError("无效参数") # 使用示例 a = create_std_vector("float") # 仍支持手动传入类型字符串 b = create_std_vector([1.0, 2.0]) # 自动推断为float类型 c: StdVectorList[int] = create_std_vector([1,2,3]) # 类型标注清晰
方案3:用枚举类约束vec_type输入
定义枚举类统一管理合法的vec_type选项,用户必须传入枚举成员,彻底避免字符串拼写错误,内部将枚举值转为对应的C++类型字符串。
修改后的代码:
from collections.abc import MutableSequence from enum import Enum from typing import Generic, TypeVar import ROOT class VectorType(Enum): FLOAT = "float" INT = "int" STRING = "string" DOUBLE = "double" T = TypeVar("T", float, int, str, float) class StdVectorList(MutableSequence, Generic[T]): """A python list interface to ROOT's std::vector""" def __init__(self, vec_type: VectorType, value: list[T] = []): """ Args: vec_type: C++类型枚举 value: 用于初始化的列表 """ self._vector = ROOT.vector(vec_type.value)(value) self.vec_type = vec_type.value # 使用示例 a = StdVectorList(VectorType.FLOAT) # 只能传入枚举成员 # b = StdVectorList("float") # 类型检查工具会报错,必须传入VectorType枚举
内容的提问来源于stack exchange,提问作者Lech Wiktor Piotrowski
相关产品推荐
相关产品推荐

