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

mypy对*args、**kwargs的里氏替换原则应用及代码校验疑问

里氏替换原则与mypy对*args/**kwargs的特殊处理

首先明确里氏替换原则(LSP)的核心要求:子类必须能无缝替换父类,所有合法调用父类方法的方式,都必须能合法调用子类方法,且不破坏程序正确性。

为什么你的代码能通过mypy校验?

当父类Base的f方法定义为*args: Any, **kwargs: Any时,mypy会将这个签名视为「接受任意数量、任意类型的位置参数和关键字参数」,并放宽对子类方法签名的检查,原因在于:

  • 这种万能签名通常用于表示「方法参数由子类具体实现决定」的场景,mypy默认允许子类在此场景下定义更具体的参数列表;
  • 静态类型检查层面,mypy假设使用父类类型的代码会遵循子类的参数要求(比如通过父类引用调用f时,会传入batch和train参数)。

但要注意,这其实存在运行时违反LSP的风险:比如以下代码能通过mypy校验,但运行时会直接报错:

def call_f(obj: Base) -> int:
    return obj.f()  # 父类签名允许无参数调用,但子类C的f需要两个参数

mypy没有检测到这个问题,是因为它只做静态签名兼容性检查,不会枚举所有可能的调用场景。

为什么移除*args或**kwargs时校验失败?

当你移除其中一个可变参数后,父类的f方法不再是「万能」签名,mypy会严格按照LSP规则检查子类签名:

  • 移除**kwargs,父类签名为*args: Any:父类允许传入任意数量的位置参数,但子类C的f只接受2个位置参数。此时如果有代码通过父类引用调用obj.f(1,2,3)(3个位置参数),子类无法处理,违反LSP,mypy报错;
  • 移除*args,父类签名为**kwargs: Any:父类允许传入任意关键字参数,但子类C的f只接受batch和train。此时如果有代码调用obj.f(epoch=10)(不存在的关键字参数),子类无法处理,违反LSP,mypy报错。

只有当父类同时声明*args: Any和**kwargs: Any时,mypy才会认为子类的具体参数列表是兼容的——尽管这在部分运行时场景下违反LSP,但这是mypy针对这种特殊签名的设计规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 04:20:24