在TypeVar上使用Unpack动态生成函数签名遇mypy错误求助
问题:基类泛型TypedDict结合Unpack触发mypy错误
尝试为_AbstractGameObject的子类动态生成函数签名,已在子类中成功对具体TypedDict执行Unpack操作,但在基类中定义Unpack时,_AbstractGameObject.load方法出现mypy错误:参数中的Unpack项必须是TypedDict [misc]。D是绑定了TypedDict的泛型类型变量,却无法被Unpack,想确认这是实验特性的局限还是有可行的实现方式?
代码示例:
from abc import ABC from dataclasses import dataclass from pathlib import Path from typing import Generic, Self, TypedDict, TypeVar, Unpack D = TypeVar("D", bound="_GameObjectDict") class _GameObjectDict(TypedDict): name: str class AssetDict(_GameObjectDict): path: Path @dataclass class _AbstractGameObject(ABC, Generic[D]): name: str @classmethod def load(cls, **kwargs: Unpack[D]) -> Self: # <- 错误提示:**参数中的Unpack项必须是TypedDict [misc] return cls(**kwargs) @dataclass class _GameObject(_AbstractGameObject[D], Generic[D]): def to_dict(self): return _GameObjectDict(name=self.name) @dataclass(kw_only=True) class Asset(_GameObject[AssetDict]): path: Path
原因与解决方案
原因说明
这是当前mypy对Unpack特性的支持局限:Unpack目前仅能直接作用于具体的TypedDict类型,无法直接用于泛型类型变量——即便该变量已经通过bound约束为TypedDict子类。mypy在基类层面无法静态推断泛型变量D的具体类型,因此会抛出错误。
可行实现方式
方式一:改为接收字典参数(推荐)
调整基类load方法的参数为TypedDict实例,而非关键字参数拆包,这样mypy可以正确识别类型约束:
@dataclass class _AbstractGameObject(ABC, Generic[D]): name: str @classmethod def load(cls, data: D) -> Self: return cls(**data) # 调用示例 Asset.load(AssetDict(name="texture", path=Path("./assets/texture.png")))
方式二:子类重载load方法保留关键字参数
如果需要保留关键字参数的调用方式,可以在基类中简化参数定义,然后在子类中重载load方法并使用具体的Unpack:
@dataclass class _AbstractGameObject(ABC, Generic[D]): name: str @classmethod def load(cls, **kwargs) -> Self: return cls(**kwargs) @dataclass(kw_only=True) class Asset(_GameObject[AssetDict]): path: Path @classmethod def load(cls, **kwargs: Unpack[AssetDict]) -> Self: return super().load(**kwargs) # 调用示例 Asset.load(name="texture", path=Path("./assets/texture.png"))
方式三:临时抑制mypy错误(不推荐)
如果必须在基类中使用Unpack[D],可以通过type: ignore[misc]暂时抑制错误,但会削弱类型检查的严谨性:
@classmethod def load(cls, **kwargs: Unpack[D]) -> Self: # type: ignore[misc] return cls(**kwargs)
内容的提问来源于stack exchange,提问作者James N
相关产品推荐
相关产品推荐

