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

如何正确为自定义MutableMapping实现添加类型注解?

问题:重写MutableMapping的update方法时mypy签名不兼容报错

我编写了如下继承自MutableMapping的子类:

from typing import Hashable, Any, MutableMapping
from _typeshed import SupportsKeysAndGetItem

class MyMutableMapping(MutableMapping[Hashable, Any]):
    def update(self, other: SupportsKeysAndGetItem[Hashable, Any], /, **kwargs: Any) -> None:
        pass

但mypy对重写的update方法签名提出报错:

test.py:5: error: Signature of "update" incompatible with supertype "MutableMapping"  [override]
test.py:5: note:      Superclass:
test.py:5: note:          @overload
test.py:5: note:          def update(self, SupportsKeysAndGetItem[Hashable, Any], /, **kwargs: Any) -> None
test.py:5: note:          @overload
test.py:5: note:          def update(self, Iterable[tuple[Hashable, Any]], /, **kwargs: Any) -> None
test.py:5: note:          @overload
test.py:5: note:          def update(self, **kwargs: Any) -> None
test.py:5: note:      Subclass:
test.py:5: note:          def update(self, SupportsKeysAndGetItem[Hashable, Any], /, **kwargs: Any) -> None
Found 1 error in 1 file (checked 1 source file)

我尝试复制mypy提示的父类签名,但仍然无法解决问题。请问我哪里出错了?

编辑:我已在mypy的GitHub问题追踪器提交了一个issue。


解答

问题核心是MutableMapping的update方法包含三个重载签名,你只实现了其中一种情况,mypy要求子类必须覆盖父类所有重载,或者提供一个兼容所有输入场景的单一签名。

解决方法1:实现所有重载版本

导入Iterable和overload,先声明所有三个重载的签名,再编写兼容所有情况的具体实现:

from typing import Hashable, Any, MutableMapping, Iterable, overload
from _typeshed import SupportsKeysAndGetItem

class MyMutableMapping(MutableMapping[Hashable, Any]):
    @overload
    def update(self, other: SupportsKeysAndGetItem[Hashable, Any], /, **kwargs: Any) -> None: ...
    @overload
    def update(self, other: Iterable[tuple[Hashable, Any]], /, **kwargs: Any) -> None: ...
    @overload
    def update(self, **kwargs: Any) -> None: ...
    
    def update(self, other: SupportsKeysAndGetItem[Hashable, Any] | Iterable[tuple[Hashable, Any]] | None = None, /, **kwargs: Any) -> None:
        # 处理传入的映射对象或键值对序列
        if other is not None:
            if hasattr(other, "__getitem__"):
                for key in other:
                    self[key] = other[key]
            else:
                for key, value in other:
                    self[key] = value
        # 处理关键字参数
        for key, value in kwargs.items():
            self[key] = value

解决方法2:使用兼容的单一签名

如果不想声明多个重载,可以直接定义一个能接收所有合法输入的签名,让mypy判定其兼容父类的所有重载:

from typing import Hashable, Any, MutableMapping, Iterable, Union
from _typeshed import SupportsKeysAndGetItem

class MyMutableMapping(MutableMapping[Hashable, Any]):
    def update(self, other: Union[SupportsKeysAndGetItem[Hashable, Any], Iterable[tuple[Hashable, Any]]] | None = None, /, **kwargs: Any) -> None:
        # 实现逻辑同上
        if other is not None:
            if hasattr(other, "__getitem__"):
                for key in other:
                    self[key] = other[key]
            else:
                for key, value in other:
                    self[key] = value
        for key, value in kwargs.items():
            self[key] = value

为什么会报错?

父类MutableMapping的update支持三种合法调用方式:

  1. 传入一个映射类对象(如dict,对应SupportsKeysAndGetItem类型)
  2. 传入可迭代的键值对元组序列(如[(k1, v1), (k2, v2)])
  3. 直接传入关键字参数(如update(a=1, b=2))

你的子类只处理了第一种情况,因此mypy判定签名与父类不兼容。即使复制了父类的单个重载,也必须覆盖全部重载场景,或者用一个兼容的签名统合所有情况。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:40:33