You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

子类构造函数参数用父类类型的子类,mypy报错该如何解决?

问题描述

我定义了父类Parent与子类Child的结构:父类构造函数接收ParentType类型的参数,子类构造函数接收ParentType的子类ChildType类型的参数。代码能正常运行,但mypy会报错——访问child.a.param_2时,提示ParentType没有param_2属性,因为它将child.a的类型推断为父类中的ParentType。相关代码如下:

class ParentType:
    def __init__(self, param_1: int):
        self.param_1 = param_1


class ChildType(ParentType):
    def __init__(self, param_1: int, param_2: int):
        super().__init__(param_1=param_1)
        self.param_2 = param_2


class Parent:
    def __init__(self, a: ParentType):
        self.a = a


class Child(Parent):
    def __init__(self, a: ChildType):
        super().__init__(a=a)


child_type = ChildType(param_1=1, param_2=2)
child = Child(a=child_type)
print(child.a.param_1)  # 正常运行
print(child.a.param_2)  # 正常运行,但mypy报错:"ParentType" has no attribute "param_2"; maybe "param_1"?
正确实现方式

最优雅且可复用的解决方法是给父类Parent使用泛型,让它能关联具体的类型参数,这样子类可以明确指定自身属性的类型,让mypy正确推断。

修改后的代码如下:

from typing import Generic, TypeVar

# 定义类型变量,约束为ParentType及其子类
T = TypeVar('T', bound='ParentType')

class ParentType:
    def __init__(self, param_1: int):
        self.param_1 = param_1

class ChildType(ParentType):
    def __init__(self, param_1: int, param_2: int):
        super().__init__(param_1=param_1)
        self.param_2 = param_2

class Parent(Generic[T]):
    def __init__(self, a: T):
        self.a: T = a

class Child(Parent[ChildType]):
    def __init__(self, a: ChildType):
        super().__init__(a=a)

child_type = ChildType(param_1=1, param_2=2)
child = Child(a=child_type)
print(child.a.param_1)  # 正常运行,mypy无报错
print(child.a.param_2)  # 正常运行,mypy无报错

关键说明

  • 导入Generic和TypeVar,定义绑定到ParentType的类型变量T,确保只能传入ParentType或其子类作为类型参数。
  • 让Parent类继承Generic[T],并将构造函数参数a和实例属性self.a都标注为类型T,这样父类的属性类型会跟随泛型参数动态变化。
  • 子类Child继承Parent[ChildType],明确指定泛型参数为ChildType,此时mypy就能准确推断出child.a的类型是ChildType,访问param_2不会再报错。

备选方案(简单场景适用)

如果只是简单场景,也可以在子类Child中重新注解a的类型,直接覆盖父类的类型标注:

class Child(Parent):
    a: ChildType
    def __init__(self, a: ChildType):
        super().__init__(a=a)

不过这种方式灵活性较差,当父类逻辑复杂或需要多个子类对应不同类型时,泛型方案更合适。

内容的提问来源于stack exchange,提问作者KOB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 06:23:15