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

如何为继承自dict的类的__ior__运算符添加类型注解?

问题分析与解决方案

核心原因

MyPy对运算符重载的签名有严格的兼容性要求,尤其是配对运算符(如__or__/__ior__)以及继承内置类型时:

  1. 配对运算符一致性:__or__(|)和__ior__(|=)的参数类型必须兼容,返回类型也需要符合逻辑一致性——__or__返回新实例,__ior__返回原地修改后的self。
  2. Liskov替换原则:子类的方法签名不能比父类更严格。因为MyDict继承自dict,你的__ior__必须接受dict.__ior__支持的所有参数类型(即Mapping[Any, Any]),同时返回类型可以是子类(协变返回,MyPy允许)。
  3. 最初的错误是因为__ior__只接受Any而__or__的签名不匹配,后续重载没覆盖父类的参数范围,导致和dict.__ior__的签名冲突。

正确的类型注解实现

以下是让MyPy通过的示例代码:

from typing import Mapping, overload, Any, TypeVar

K = TypeVar('K')
V = TypeVar('V')

class MyDict(dict[K, V]):
    @overload
    def __or__(self, other: Mapping[K, V]) -> 'MyDict[K, V]': ...
    @overload
    def __or__(self, other: Mapping[Any, Any]) -> 'MyDict[Any, Any]': ...
    def __or__(self, other: Mapping[Any, Any]) -> 'MyDict[Any, Any]':
        # 替换为你的实际实现逻辑
        result = MyDict(self)
        result.update(other)
        return result

    @overload
    def __ior__(self, other: Mapping[K, V]) -> 'MyDict[K, V]': ...
    @overload
    def __ior__(self, other: Mapping[Any, Any]) -> 'MyDict[Any, Any]': ...
    def __ior__(self, other: Mapping[Any, Any]) -> 'MyDict[Any, Any]':
        super().__ior__(other)
        return self

关键说明

  • 用@overload同时提供精确泛型和兼容父类的签名,既满足类型精确性,又不违反父类的方法契约。
  • __or__和__ior__的参数类型范围一致,确保配对运算符的兼容性。
  • __ior__返回MyDict而不是dict,这符合协变返回类型规则,MyPy允许子类方法返回更具体的类型。

兼容性规则的查找途径

  1. MyPy官方文档:在「运算符重载」章节中,明确了配对运算符的签名一致性要求,以及子类重载父类方法的Liskov替换原则。
  2. PEP规范:PEP 484(类型提示)和PEP 544(结构化子类型)定义了泛型类和运算符注解的基础规则,其中原地运算符(如__ior__)的返回类型应该是Self类型(Python 3.11+支持,低版本可以用类名字符串)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:07:18