首页 > 解决方案 > 如何确保两个参数具有可比性?

问题描述

我实现了一个类似于这个简化版本的 Interval 类:

class Interval:
    def __init__(self, left, right):
        assert left <= right
        self.left = left
        self.right = right

    def intersect(self, other: Interval) -> Optional[Interval]:
        if other.left < self.left:
            self, other = other, self
        # self starts first

        if self.right < other.left:
            return None

        return Interval(other.left, min(self.right, other.right))

我现在想知道在这两种情况下如何添加好的类型注释。我的主要问题是关于构造函数:我怎样才能确保左右是可比较的?它们可以是字符串、数字或任何实现__le__. mypy可以检查吗?

标签: pythonpython-3.8mypy

解决方案


Python 的类型注解不足以表达这一点。

您可以编写一个协议来指定比较方法的存在,但没有办法指定对象可以相互比较。此外, mypy 不理解functools.total_ordering,因此任何使用它的类都会出现虚假错误。

(另外,每个类在技术上都有一套完整的 6 个比较方法,由于object's 比较方法是如何从其 C 级tp_richcompare插槽生成的细节,但 mypy 不这么认为。)


(不足的)协议看起来像

class Comparable(typing.Protocol):
    def __eq__(self, other): ...
    def __ne__(self, other): ...
    def __lt__(self, other): ...
    def __le__(self, other): ...
    def __gt__(self, other): ...
    def __ge__(self, other): ...

请注意,我没有在方法上添加任何注释。这是故意的——“明显”的注释def __eq__(self, other: Comparable) -> bool是错误的。

比较方法应该接受任意其他对象,NotImplemented如果它们不识别其他对象则返回。这意味着other除了object. 此外,mypy 不理解Union[bool, type(NotImplemented)]. 此外,在某些情况下,比较可能会返回 abool或以外的结果NotImplemented- 例如,比较两个 NumPy 标量将返回一个numpy.bool_不是布尔值的实例,但大多数情况下都像一个。


推荐阅读