Python如何实现类似TypeScript的索引访问类型 引用类字段类型做注解
解决方案
基础场景(对标TypeScript示例)
Python完全支持你想要的类似TypeScript索引访问类型的能力,和User["foo"]完全等效的写法就是User['foo'],不需要加typing.Type包裹。
你之前的写法报错是因为误用了typing.Type:Type[User]表示User类本身的类型,而非User实例的类型,自然无法拿到实例字段的类型。
修正后的可通过类型检查的代码如下:
from __future__ import annotations import typing import pydantic class User(pydantic.BaseModel): foo: int def f(foo: User['foo']): print(foo) user = User(foo=42) f(user.foo)
注意事项:在文件顶部加from __future__ import annotations是为了让类型注解延迟求值,运行时不会执行User['foo']的索引逻辑,避免非Pydantic类或者低版本Python运行时报错,类型检查器可以正常识别该注解。该写法目前对mypy、pyright等主流Python类型检查器均生效。
泛型场景
索引访问类型同样可以作用于泛型的TypeVar上,你标记??的位置直接按以下规则填写即可:
- 要获取
TResult.items的类型直接写TResult['items'] - 要获取列表
items的元素类型直接写TResult['items'][int]
修正后的完整代码如下:
from __future__ import annotations import abc from typing import TypeVar, Generic, Literal from pydantic.generics import GenericModel TResultItem = TypeVar("TResultItem") class ResultBase( GenericModel, Generic[TResultItem] ): status: Literal["success", "failure"] items: list[TResultItem] TResult = TypeVar("TResult", bound=ResultBase) class CalculatorBase(Generic[TResult], abc.ABC): def calculate(self) -> TResult: try: items: TResult['items'] = [] for i in range(10): items.append( self._calculate_one(i) ) except Exception: return self._create_result( "failure", [] ) else: return self._create_result( "success", items ) @abc.abstractmethod def _calculate_one(self, i: int) -> TResult['items'][int]: ... @abc.abstractmethod def _create_result( self, status: Literal["success", "failure"], items: TResult['items'], ) -> TResult: ...
如果你觉得取列表元素的写法不够直观,也可以调整泛型参数定义,把条目类型也作为CalculatorBase的泛型参数,写法兼容性更好也更易读:
TResultItem = TypeVar("TResultItem") TResult = TypeVar("TResult", bound=ResultBase) class CalculatorBase(Generic[TResult, TResultItem], abc.ABC): def calculate(self) -> TResult: try: items: list[TResultItem] = [] # 其余逻辑不变 # ... @abc.abstractmethod def _calculate_one(self, i: int) -> TResultItem: ... @abc.abstractmethod def _create_result( self, status: Literal["success", "failure"], items: list[TResultItem], ) -> TResult: ...
内容的提问来源于stack exchange,提问作者peter554
相关产品推荐
相关产品推荐

