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

继承Protocol的基类使用super().__init__()无法初始化变量问题

问题解析:继承Protocol时super().init()为何不生效?

核心原因

Protocol是Python类型提示系统的专属结构,仅用于静态类型检查,程序运行时它属于"虚拟基类",不会被纳入实际的方法解析顺序(MRO)执行链。也就是说,当类继承自Protocol时,Python运行时不会把它当作真正的父类处理,super().__init__()会直接跳过Protocol,去调用下一个实际存在的父类(通常是object)的构造函数。

这就是代码中P的__init__从未执行的根本原因——运行时它完全没被当作A的父类来调用。

对比验证

  • 当P不继承Protocol时,它是普通类,会被正常纳入MRO,super().__init__()会按顺序调用P的构造函数,y能被正确赋值。
  • 当P继承Protocol时,运行时忽略这个"虚拟父类",P的__init__完全不会执行,导致a.y未定义,触发AttributeError。

解决方案

根据需求选择以下两种处理方式:

1. 仅用Protocol做类型约束

如果P只是用来定义类必须符合的结构(仅用于类型检查),不要在Protocol里写需要运行时执行的代码,直接在子类中实现所有属性赋值:

from typing import Protocol

class P(Protocol):
    y: str  # 仅声明类型约束

class A(P):
    x: str
    y: str  # 明确符合Protocol的类型要求

    def __init__(self, x: str, y: str) -> None:
        self.x = x
        self.y = y  # 直接赋值y

a = A("x", "y")
assert a.x == "x"
assert a.y == "y"  # 断言通过

2. 需要运行时基类逻辑,改用ABC

如果需要基类提供实际的运行时逻辑(比如构造函数里的属性赋值),不要用Protocol,改用abc.ABC(抽象基类),它会被正常纳入MRO,super()调用也能正常工作:

from abc import ABC

class P(ABC):
    y: str

    def __init__(self, y: str) -> None:
        self.y = y

class A(P):
    x: str

    def __init__(self, x: str, y: str) -> None:
        self.x = x
        super().__init__(y=y)  # 正常调用P的构造函数

a = A("x", "y")
assert a.x == "x"
assert a.y == "y"  # 断言通过

结论

  • 继承Protocol时,不能依赖super()调用Protocol中的方法,因为Protocol在运行时不参与实际继承链。
  • Protocol的作用是定义类型契约,仅用于静态检查;如果需要运行时的继承逻辑,使用普通类或抽象基类(ABC)。

内容的提问来源于stack exchange,提问作者Jamie.Sgro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 19:10:30