如何让Dataclass可选字段缺失时自动推断且符合Mypy类型检查?
问题描述
我希望我的dataclass拥有一个字段,该字段既可以手动提供,也可以在未提供时,在初始化阶段从其他字段自动推断。示例代码如下:
from collections.abc import Sized from dataclasses import dataclass from typing import Optional @dataclass class Foo: data: Sized index: Optional[list[int]] = None def __post_init__(self): if self.index is None: self.index = list(range(len(self.data))) reveal_type(Foo.index) # Union[None, list[int]] reveal_type(Foo([1,2,3]).index) # Union[None, list[int]]
需要实现以下目标:
- 符合mypy类型检查要求
- 保证
index字段的类型为list[int]
我曾考虑使用default_factory(list),但无法区分用户传入index=[]和默认值的情况。除了使用index: list[int] = None # type: ignore[assignment]之外,是否有合适的解决方案?
解决方案
方法一:使用InitVar分离初始化参数与实例字段
利用dataclasses.InitVar将仅用于初始化的可选参数和实例的必填字段拆分,既支持手动传入index,也能在未传入时自动生成,同时让mypy正确识别实例字段的类型:
from collections.abc import Sized from dataclasses import dataclass, InitVar from typing import Optional @dataclass class Foo: data: Sized _index: InitVar[Optional[list[int]]] = None index: list[int] def __post_init__(self, _index: Optional[list[int]]): if _index is not None: self.index = _index else: self.index = list(range(len(self.data))) reveal_type(Foo.index) # list[int] reveal_type(Foo([1,2,3]).index) # list[int]
_index是仅用于初始化的参数,类型为Optional[list[int]],默认值设为None- 实例字段
index直接声明为list[int],无需标记为可选类型 __post_init__中根据初始化参数的值确定index的最终值,mypy能准确识别实例的index类型始终为list[int]
方法二:自定义唯一默认标记值
如果不想使用InitVar,可以定义一个独特的标记对象,用来区分用户主动传入的空列表和未传入参数的场景:
from collections.abc import Sized from dataclasses import dataclass from typing import Optional # 定义一个全局唯一的标记对象,和用户可能传入的任何值都不重复 _UNSET = object() @dataclass class Foo: data: Sized index: list[int] = _UNSET # type: ignore[assignment] def __post_init__(self): if self.index is _UNSET: self.index = list(range(len(self.data))) # 可选:添加类型校验,确保用户传入的index是list[int] reveal_type(Foo.index) # list[int] reveal_type(Foo([1,2,3]).index) # list[int] # 支持用户传入空列表,不会触发自动生成逻辑 reveal_type(Foo([1,2,3], index=[]).index) # list[int]
- 用
_UNSET作为默认值,彻底区分用户传入的[]和未传参的情况 - 仅忽略默认值的类型不匹配警告,实例的
index类型始终为list[int],mypy能正确识别实例化后的字段类型
内容的提问来源于stack exchange,提问作者Hyperplane
相关产品推荐
相关产品推荐

