能否为类字典自定义对象添加TypedDict风格的类型提示?
解决方案:为自定义类添加TypedDict风格的类型提示
你的核心问题是:TypedDict是专门为原生字典设计的类型标注,自定义类即便实现了字典的存取方法,类型检查器也不会默认将其与TypedDict类型划等号。不过完全可以通过类型系统的特性实现兼容,以下是针对不同场景的解决方案:
场景1:可以修改MyDictImplementation类代码
给自定义类添加泛型支持,让它可以绑定到对应的TypedDict结构,这样类型检查器就能识别它的结构兼容性:
import typing from typing import Generic, TypeVar, TypedDict # 定义类型变量,绑定到Mapping类型(包含TypedDict) T = TypeVar('T', bound=typing.Mapping) class MyDictImplementation(Generic[T]): def __init__(self, values: T): self.values: T = values def __setitem__(self, key: typing.Any, value: typing.Any) -> None: self.values[key] = value def __getitem__(self, item: typing.Any) -> typing.Any: return self.values[item] def __repr__(self) -> str: return f'{self.__class__.__name__}({self.values.__repr__()})' # 原TypedDict定义保持不变 class StatusState(typing.TypedDict): enabled: bool group: str class States(typing.TypedDict): states: typing.Dict[int, StatusState] class Project(typing.TypedDict): project: States # 修改函数参数,同时接受原生Project字典和泛型自定义类实例 def typing_test(input_: typing.Union[Project, MyDictImplementation[Project]]): pass # 原生字典正常使用 foo: Project = {'project': {"states": {0: {"enabled": True, "group": 'Meta'}}}} typing_test(foo) # 自定义类实例指定泛型类型后可通过检查 bar: MyDictImplementation[Project] = MyDictImplementation({ 'project': MyDictImplementation({ 'states': MyDictImplementation({ 0: MyDictImplementation({'enabled': True, 'group': 'Meta'}) }) }) }) typing_test(bar) # 类型检查通过
场景2:无法修改MyDictImplementation类代码
使用Protocol定义一个符合TypedDict结构的访问协议,类型检查器会自动识别实现了__getitem__/__setitem__的自定义类是否符合该协议:
import typing from typing import Protocol, TypedDict, Literal # 原自定义类保持不变 class MyDictImplementation: def __init__(self, values): self.values = values def __setitem__(self, key, value): self.values[key] = value def __getitem__(self, item): return self.values[item] def __repr__(self): return f'{self.__class__.__name__}({self.values.__repr__()})' # 原TypedDict定义保持不变 class StatusState(typing.TypedDict): enabled: bool group: str class States(typing.TypedDict): states: typing.Dict[int, StatusState] class Project(typing.TypedDict): project: States # 定义对应Project结构的协议 class ProjectProtocol(Protocol): def __getitem__(self, key: Literal['project']) -> States: ... def __setitem__(self, key: Literal['project'], value: States) -> None: ... # 函数参数接受原生Project或符合协议的自定义类 def typing_test(input_: typing.Union[Project, ProjectProtocol]): pass foo: Project = {'project': {"states": {0: {"enabled": True, "group": 'Meta'}}}} typing_test(foo) bar = MyDictImplementation({ 'project': MyDictImplementation({ 'states': MyDictImplementation({ 0: MyDictImplementation({'enabled': True, 'group': 'Meta'}) }) }) }) typing_test(bar) # 类型检查通过
临时权宜方案(不推荐)
如果以上方法都无法使用,可以用typing.cast强制类型转换绕过检查,但这会失去类型检查的意义,仅适合临时场景:
typing_test(typing.cast(Project, bar))
内容的提问来源于stack exchange,提问作者Jerakin
相关产品推荐
相关产品推荐

