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

如何让mypy不将自定义类视为object的子类型并限制类型兼容?

如何让mypy禁止自定义类与非同类实例比较,并阻止其传入期望object的函数?

一、禁止MyClass与非同类实例的==比较(触发mypy类型错误)

要让MyClass(5) == 5触发mypy报错,需要通过精确的__eq__类型签名配合mypy的严格模式实现:

  1. 使用@overload为__eq__定义仅接受Self类型的类型签名,同时保留运行时对object参数的兼容处理:
from typing import Self, overload

class MyClass:
    def __init__(self: Self, x: int):
        self.x = x

    # 类型检查层面:仅允许与MyClass实例比较
    @overload
    def __eq__(self: Self, other: Self) -> bool: ...
    
    # 运行时层面:处理所有object类型,非同类返回NotImplemented
    def __eq__(self: Self, other: object) -> bool:
        if not isinstance(other, MyClass):
            return NotImplemented
        return self.x == other.x
  1. 开启mypy的严格检查模式:
    运行mypy时添加--strict-equality和--strict(或至少--disallow-untyped-defs)参数:
mypy test.py --strict-equality --strict

此时mypy会对MyClass(5) == 5抛出类型错误:

error: Unsupported operand types for == ("MyClass" and "int")

二、禁止将MyClass实例传入期望object的函数

这一需求违背Python类型系统的里氏替换原则(所有自定义类都是object的子类,类型检查器默认允许子类赋值给父类类型),标准工具无法直接实现,但可通过以下方案近似达成:

方案1:修改函数参数类型为排除MyClass的自定义Protocol

定义一个排除MyClass的Protocol,配合类型守卫限制函数参数:

from typing import Protocol, TypeGuard

class NotMyClass(Protocol):
    pass

def is_not_myclass(obj: object) -> TypeGuard[NotMyClass]:
    return not isinstance(obj, MyClass)

def abstract_comparator(a: NotMyClass, b: NotMyClass) -> bool:
    # 可选:运行时补充断言检查
    assert is_not_myclass(a) and is_not_myclass(b)
    return a == b

此时传入MyClass实例会触发mypy类型错误,但需要修改目标函数的类型注解。

方案2:运行时检查补充

如果无法修改函数类型注解,可在函数内部添加运行时类型检查,作为类型检查的兜底:

def abstract_comparator(a: object, b: object) -> bool:
    if isinstance(a, MyClass) or isinstance(b, MyClass):
        raise TypeError("MyClass instances are not allowed in this function")
    return a == b

方案3:自定义mypy插件

通过编写mypy插件实现自定义类型检查规则,拦截MyClass实例赋值给object类型参数的场景。这需要熟悉mypy的插件开发API,适合复杂场景的长期维护。


内容的提问来源于stack exchange,提问作者Филя Усков

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 18:53:11