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

如何为泛型重写方法获取正确的类型标注?

解决Container子类__contains__方法的类型兼容问题

问题背景

我想实现一个继承自collections.abc.Container的自定义容器类,先回顾Container协议的定义:

@runtime_checkable
class Container(Protocol[_T_co]):
    @abstractmethod
    def __contains__(self, __x: object) -> bool: ...

我的初始实现代码如下:

from collections.abc import Container
from typing import Generic, TypeVar

_ContainerType = TypeVar('_ContainerType')

class MyContainer(Container[_ContainerType], Generic[_ContainerType]):

    def _find(self, __value: _ContainerType) -> int:
        '''返回指定元素的索引,若容器中无该元素则返回-1'''
        return -1

    def __contains__(self, __x: _ContainerType) -> bool:
        return self._find(__x) >= 0

运行mypy --strict --show-error-context .后出现报错:

my_container.py: note: In member "__contains__" of class "MyContainer":
my_container.py:12: error: Argument 1 of "__contains__" is incompatible with supertype "Container"; supertype defines the argument type as "object"
my_container.py:12: note: This violates the Liskov substitution principle
my_container.py:12: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides

我把__contains__的参数类型改成基类要求的object后:

def __contains__(self, __x: object) -> bool:
        return self._find(__x) >= 0

又出现新的报错:

my_container.py: note: In member "__contains__" of class "MyContainer":
my_container.py:13: error: Argument 1 to "_find" of "MyContainer" has incompatible type "object"; expected "_ContainerType"

两次报错都是合理的,但我该怎么解决?其他场景里我会用isinstance(...)做类型检查,让mypy接受类型转换,但这里没有固定类型可以用。

解决方案

核心思路是在__contains__中对传入的object类型参数做类型窄化,结合typing.cast让mypy认可类型转换,同时保证运行时逻辑的合理性。

修改后的代码如下:

from collections.abc import Container
from typing import Generic, TypeVar, cast

_ContainerType = TypeVar('_ContainerType')

class MyContainer(Container[_ContainerType], Generic[_ContainerType]):

    def _find(self, __value: _ContainerType) -> int:
        '''返回指定元素的索引,若容器中无该元素则返回-1'''
        return -1

    def __contains__(self, __x: object) -> bool:
        # 告诉mypy该object可被当作_ContainerType处理
        candidate = cast(_ContainerType, __x)
        # 可选:针对具体类型添加运行时检查,比如if isinstance(candidate, int):
        return self._find(candidate) >= 0

关键说明

  1. 遵守里氏替换原则:保持__contains__的参数类型为object,与基类定义一致,避免类型兼容性问题。
  2. 类型断言的合理性:使用cast是因为我们明确知道容器的元素类型是_ContainerType,传入的__x如果属于该类型才会被_find识别,否则_find返回-1,符合__contains__返回bool的要求。
  3. 可选的运行时校验:如果容器针对特定类型(如str、int),可以在cast后添加isinstance检查,既保证类型安全,又能让mypy完全认可类型转换;泛型场景下跳过检查也符合Container协议的设计——__contains__本身允许传入任意object。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 14:25:18