如何为泛型重写方法获取正确的类型标注?
解决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
关键说明
- 遵守里氏替换原则:保持
__contains__的参数类型为object,与基类定义一致,避免类型兼容性问题。 - 类型断言的合理性:使用
cast是因为我们明确知道容器的元素类型是_ContainerType,传入的__x如果属于该类型才会被_find识别,否则_find返回-1,符合__contains__返回bool的要求。 - 可选的运行时校验:如果容器针对特定类型(如
str、int),可以在cast后添加isinstance检查,既保证类型安全,又能让mypy完全认可类型转换;泛型场景下跳过检查也符合Container协议的设计——__contains__本身允许传入任意object。
内容的提问来源于stack exchange,提问作者Rasc
相关产品推荐
相关产品推荐

