如何基于类属性定义为返回不可变字典的函数生成精确类型提示?
实现类属性到不可变字典的自动类型提示方案
可以实现无需手动维护TypedDict或冗余类型定义的需求,通过MyPy扩展特性和Python泛型,就能让类型检查工具自动识别与类属性结构一致的字典类型。以下是两种可行方案:
方案1:利用MyPy协议与泛型推导静态类型
如果只需要静态类型检查(MyPy/IDE识别),可以定义泛型协议,让MyPy自动将类属性映射为字典的键值类型:
from typing import TypeVar, Protocol from mypy_extensions import Unpack from types import MappingProxyType T = TypeVar("T", bound=object) class ClassDict(Protocol[T]): @classmethod def __class_getitem__(cls, cls_type: type[T]) -> dict[Unpack[T]]: ... def to_immutable_dict(obj: T) -> ClassDict[T]: # 运行时逻辑:提取类属性并转为不可变字典 from typing import get_type_hints attr_hints = get_type_hints(obj.__class__) return MappingProxyType({key: getattr(obj, key) for key in attr_hints}) # 第三方类A(类型存根已定义name: str、content: str、age: int) class A: name: str content: str age: int # 测试示例 a_instance = A() a_instance.name = "Bob" a_instance.content = "Demo" a_instance.age = 28 immutable_dict = to_immutable_dict(a_instance) # MyPy/IDE会识别immutable_dict的键结构:name(str)、content(str)、age(int) reveal_type(immutable_dict["name"]) # MyPy将输出"str"
- 依赖
mypy-extensions库,需提前安装:pip install mypy-extensions Unpack[T]是MyPy专属扩展,PyCharm等IDE需开启MyPy兼容模式才能正常识别
方案2:Python 3.11+动态生成TypedDict(兼容运行时+静态检查)
如果需要同时支持运行时逻辑和静态类型检查,可以动态创建TypedDict并通过类型转换让MyPy识别:
from typing import TypeVar, get_type_hints, TypedDict, cast from types import MappingProxyType T = TypeVar("T", bound=object) def to_immutable_dict(obj: T) -> TypedDict[type(T)]: # 动态生成与类属性匹配的TypedDict class_name = f"{obj.__class__.__name__}Dict" attr_types = get_type_hints(obj.__class__) GeneratedDict = TypedDict(class_name, attr_types) # 生成不可变字典并转换为目标类型 return cast(GeneratedDict, MappingProxyType({k: getattr(obj, k) for k in attr_types})) # 使用方式与方案1一致,MyPy会自动识别字典的键值类型
- 无需额外依赖,但静态检查效果略逊于方案1,需确保第三方类有完整的类型存根
关键注意点
- 必须保证第三方类A有完整的类型存根(
.pyi文件),否则get_type_hints和MyPy无法正确识别属性类型 - 如果类A存在继承属性,
get_type_hints会自动包含父类中定义的属性(前提是父类的类型存根也完整)
内容的提问来源于stack exchange,提问作者Marcin Gordziejewski
相关产品推荐
相关产品推荐

