继承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
相关产品推荐
相关产品推荐

