Python是否有TypeScript中Pick类型的等效实现?
在Python中实现TypeScript风格的Pick与Add类型功能
实现Pick函数
我们可以利用dataclasses.make_dataclass动态生成仅包含指定字段的数据类,同时保留原类型的类型提示:
from dataclasses import dataclass, make_dataclass from typing import TypeVar, Tuple, Type, get_type_hints T = TypeVar('T') def Pick(cls: Type[T], fields: Tuple[str, ...]) -> Type: # 获取原类的类型提示 type_hints = get_type_hints(cls) # 检查指定字段是否存在于原类中 missing_fields = [f for f in fields if f not in type_hints] if missing_fields: raise ValueError(f"字段 {missing_fields} 不存在于 {cls.__name__} 中") # 筛选出目标字段及其类型 selected_fields = [(field, type_hints[field]) for field in fields] # 生成新的数据类 return make_dataclass(f"{cls.__name__}Pick", selected_fields)
实现Add函数
类似地,我们可以生成包含原类所有字段及新增字段的数据类:
def Add(cls: Type[T], new_fields: dict[str, type]) -> Type: type_hints = get_type_hints(cls) # 检查新增字段是否与原类字段冲突 conflicting_fields = [f for f in new_fields if f in type_hints] if conflicting_fields: raise ValueError(f"字段 {conflicting_fields} 已存在于 {cls.__name__} 中") # 合并原字段与新增字段 combined_fields = list(type_hints.items()) + list(new_fields.items()) # 生成新的数据类 return make_dataclass(f"{cls.__name__}Add", combined_fields)
使用示例
from dataclasses import dataclass from typing import List @dataclass class Foo: x: int y: float z: str # 从Foo中挑选x和y字段生成Bar类 Bar = Pick(Foo, ('x', 'y')) bar = Bar(1, 2.0) print(bar) # 输出: FooPick(x=1, y=2.0) # 给Foo添加w字段生成Baz类 Baz = Add(Foo, {'w': List[int]}) baz = Baz(1, 2.0, '3', w=[1, 2, 3]) print(baz) # 输出: FooAdd(x=1, y=2.0, z='3', w=[1, 2, 3])
类型安全与mypy支持
上述实现在运行时完全类型安全,但mypy的静态分析对动态生成的类支持有限。若需要mypy完全识别生成类的字段类型,可以:
- 为生成的类添加显式协议注解:
from typing import Protocol class BarProtocol(Protocol): x: int y: float Bar: Type[BarProtocol] = Pick(Foo, ('x', 'y')) - 使用
pydantic库的create_model方法,它对动态模型的类型推断支持更完善:from pydantic import create_model Bar = create_model('Bar', __base__=Foo, include={'x', 'y'}) Baz = create_model('Baz', __base__=Foo, w=(List[int], []))
内容的提问来源于stack exchange,提问作者Cory Nezin
相关产品推荐
相关产品推荐

