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

为何typing.MutableMapping无法作为Protocol基类?如何基于其定义自定义映射协议?

这个问题我之前也碰到过,核心原因是typing.MutableMapping和typing.Sized在mypy中的类型定位不同:typing.Sized已经是PEP 544兼容的Protocol类型,而typing.MutableMapping只是collections.abc.MutableMapping(一个传统抽象基类ABC)的别名,旧版mypy会严格要求Protocol的所有基类必须是Protocol本身,所以才会抛出那个错误。

下面给你两个可行的解决方案:

方案1:升级mypy并改用collections.abc.MutableMapping作为基类

如果你的mypy版本能升级到0.910及以上,它已经支持Protocol继承自ABC类型。你只需要把基类换成collections.abc.MutableMapping,就能自动继承所有MutableMapping的抽象方法要求,不用手动编写:

from collections.abc import MutableMapping
from typing import Hashable, Protocol, TypeVar

TVarMapProt = TypeVar("TVarMapProt", bound="VariableMappingProtocol")
class VariableMappingProtocol(MutableMapping[Hashable, int], Protocol):
    """ Protocol for the type behaviour of a class which acts basically like a dict of int objects. """
    def copy(self: TVarMapProt) -> TVarMapProt:
        # 要是你用的是Python 3.11+,可以直接替换成Self类型,更简洁:
        # from typing import Self
        # def copy(self) -> Self:
        ...

这样mypy会自动把MutableMapping的所有核心方法(比如__getitem__、__setitem__)纳入结构类型检查,同时你的自定义copy()方法也会被要求实现。

方案2:手动声明核心方法(兼容旧版mypy)

如果暂时无法升级mypy,也可以手动声明MutableMapping的核心方法——结构类型检查只需要这些关键方法,不用写全所有方法:

from typing import Hashable, Protocol, TypeVar, Iterator

TVarMapProt = TypeVar("TVarMapProt", bound="VariableMappingProtocol")
class VariableMappingProtocol(Protocol):
    """ Protocol for the type behaviour of a class which acts basically like a dict of int objects. """
    def __getitem__(self, key: Hashable) -> int: ...
    def __setitem__(self, key: Hashable, value: int) -> None: ...
    def __delitem__(self, key: Hashable) -> None: ...
    def __iter__(self) -> Iterator[Hashable]: ...
    def __len__(self) -> int: ...

    def copy(self: TVarMapProt) -> TVarMapProt: ...

这种方式虽然多写了几行,但能完美兼容旧版mypy,同时保持Protocol的结构类型特性。

自定义类的正确实现方式

需要注意的是,你的自定义类不需要显式继承VariableMappingProtocol——只要实现了所有要求的方法(包括MutableMapping的核心方法和copy()),mypy就会自动识别它符合该Protocol:

from collections.abc import Iterator, Hashable
from typing import TypeVar

TCusVarMap = TypeVar("TCusVarMap", bound="CustomVariableMapping")
class CustomVariableMapping:
    """Defines all the methods that a MutableMapping does, but mapping Hashables to ints"""
    def __getitem__(self, key: Hashable) -> int:
        # 替换成你的实现逻辑
        return 0
    def __setitem__(self, key: Hashable, value: int) -> None:
        # 替换成你的实现逻辑
        pass
    def __delitem__(self, key: Hashable) -> None:
        # 替换成你的实现逻辑
        pass
    def __iter__(self) -> Iterator[Hashable]:
        # 替换成你的实现逻辑
        return iter([])
    def __len__(self) -> int:
        # 替换成你的实现逻辑
        return 0
    def copy(self: TCusVarMap) -> TCusVarMap:
        # 替换成你的实现逻辑
        return CustomVariableMapping()

如果用的是Python 3.11+,还可以用Self类型简化TypeVar的写法:

from typing import Self

class CustomVariableMapping:
    # ... 其他方法保持不变 ...
    def copy(self) -> Self:
        return CustomVariableMapping()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 03:28:11