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

Mypy为何允许重写__init__时使用不兼容的参数类型?

Mypy对__init__的特殊处理原因

  • LSP约束的是实例被创建之后的使用行为,而非实例的创建过程。LSP的核心要求是「所有接收父类实例作为参数的上下文,都可以无感知替换为子类实例」,你构造实例时主动指定类名的场景(比如Bar(12))不属于这个范畴:你本来就知道自己正在实例化哪个类,不需要和父类的构造参数对齐。
  • __init__不属于类的实例对外暴露的公共接口,只有实例化之后能被外部调用的方法/属性才属于LSP的约束范围。因此Mypy在子类定义阶段,不会对__init__、__new__这类构造相关的特殊方法做和普通实例方法一样的签名兼容校验,这是有意设计的规则,和普通方法的处理逻辑确实不同。

这个设计的合理性

  • 这种规则是符合Python生态的通用实践的:比如标准库中绝大多数抽象基类的子类,构造参数都和父类不同,但只要实现了父类要求的实例接口,就可以正常替换使用。如果强制要求构造参数和父类对齐,反而会扼杀大量合理的继承场景。
  • 如果你真的需要对构造过程做通用抽象,比如写一个接收Type[Foo]类型参数、动态实例化的函数,Mypy依然会做对应的类型校验:
    from typing import Type
    def create_foo(cls: Type[Foo], x: int) -> Foo:
        return cls(x)
    
    create_foo(Bar, 12) # Mypy此处会报错,提示Bar的__init__不接受int类型参数
    
    也就是说Mypy只会在你实际把类对象当成Type[Foo]来调用构造的时候才会做校验,不会在子类定义阶段就一刀切禁止不同的构造签名。

关于LSP的判定

你给出的示例中Bar类并没有违反LSP:只要Bar的实例完全实现了Foo对外暴露的所有实例接口,构造参数不同不会影响实例创建后的替换使用。只有当你修改__init__导致实例的属性/方法不符合父类的接口约定时,才会真正违反LSP,这种情况下Mypy也会对应抛出错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 15:57:01