Python为什么不提供默认的__le__和__ge__实现?

问题描述 投票:-1回答:2

数学上,binary relation≤是二元关系union,而二元关系≥是二元关系>和=的并集。那么,为什么有一个原因使得Python默认不以__le____lt__来实现__eq__,而没有以__ge____gt__的方式实现__eq__

默认的实现可能是这样的(但可能是出于C的考虑,例如__ne__:]

def __le__(self, other):
    result_1 = self.__lt__(other)
    result_2 = self.__eq__(other)
    if result_1 is not NotImplemented and result_2 is not NotImplemented:
        return result_1 or result_2
    return NotImplemented

def __ge__(self, other):
    result_1 = self.__gt__(other)
    result_2 = self.__eq__(other)
    if result_1 is not NotImplemented and result_2 is not NotImplemented:
        return result_1 or result_2
    return NotImplemented

这将使用户不​​必始终实现这两种方法。

这里是Python documentation(强调我的部分)中的相关段落:

默认情况下,__ne__()委托给__eq__()并求反除非是NotImplemented。没有其他暗示比较运算符之间的关系,例如,真相(x<y or x==y)的值并不表示x<=y

Note。

-以下关系始终有效,因此默认情况下在Python中实现(联合关系除外,这似乎是任意的,这是本文的原因):
  • 2 complementary关系:“ =和≠是彼此的补语”;
  • 6 converse关系*:“ =是其本身的逆向”,“≠是其自身的逆向”,“ 是彼此的逆向”和“≤和≥是彼此的逆向”;]]
  • 2 union关系:“≤是联合和=”的联合。
  • 以下关系仅对total orders有效,因此默认情况下在Python中未实现(但是,当它们由Python标准库提供的functools.total_ordering类修饰器有效时,用户可以方便地实现它们:]]

    • 4 functools.total_ordering关系:“ 和≤是彼此的互补”。

    *反向关系通过complementary在Python中实现。

    数学上,二元关系≤是二元关系和=的并集。因此,Python这样做有原因吗?

为什么要做出这个决定,只有原始作者知道,但是从手动得出的这些提示可以推断出原因:

要从单个root操作自动生成排序操作,请参见NotImplemented protocol。>>

尽管此装饰器使创建行为良好的完全有序类型变得容易,但它[[does

的代价是执行速度较慢,派生比较方法的堆栈跟踪更复杂。如果性能基准测试表明这是给定应用程序的瓶颈,则实施所有六种丰富的比较方法可能会轻松提高速度。与Python的口号“ [[显式优于隐式]对>配对,以下推理应该令人满意:

NotImplemented中的functools.total_ordering()导出实际上是免费的,它只是functools.total_ordering()的运算,即反转布尔值。

但是,从__ne____eq__的并集得出not o.__eq__(other)意味着需要调用这两种方法,如果比较足够复杂,则可能会严重影响性能,

特别是与优化的__le__单一实现。

Python使您可以通过使用__lt__装饰器显式地选择这种性能优于性能,但不会对您造成隐式影响。

[如果您尝试执行未实现的比较,而不是未实现的隐式派生比较,并且可能会创建细微的错误,这也可能会引起显式错误,这取决于您对自定义类所做的操作。 Python在这里不会为您做任何猜测,而是由您自己决定是显式实现所需的比较,还是再次显式选择加入派生的比较。

TLDR:比较运算符不需要返回__eq__。这意味着结果可能不会严格遵守“__le__is total_ordering”或类似关系。最重要的是,布尔值bool可能无法保留其语义。

自动生成特殊方法可能会无提示地导致错误行为,类似于a <= b。 (此示例还将a < b or a == b等视为比or更多。)

一个例子是通过比较运算符表达时间点。例如,automatic __bool__ is not generally applicable仿真框架(免责声明:我维护此程序包)定义了__bool__。我们可以使用比较来描述某个时间点“或之后”:


<=在2000年之后。

bool at 2000。

    [usim在2000年或之后。
  • ((time points that can be checked and waited fortime > 2000同样适用,但该限制更难解释。)
  • 值得注意的是,每个表达式都有两个特征:
  • 现在是否满足(time == 2000)和

    何时将满足

  • time >= 2000)。显然可以针对每种情况评估第一个。但是,第二个不能。

    等待<==可以通过等待/睡眠直到确切的时间点来完成。但是,等待bool(time >= 2000)需要等待时间点await (time >= 2000)。后者无法准确表示,因为对于当代数类型,没有通用的无限小但非零的数。因此,==>=的结果基本上与>不同。将plus some infinitely small delay导出为“ ==”将是错误的。因此,为了避免错误,>=定义了>>=,但没有定义> or ==。自动定义比较运算符会避免这种情况,或者错误定义运算符。

    python relationship comparison-operators partial-ordering
    2个回答
    3
    投票

    为什么要做出这个决定,只有原始作者知道,但是从手动得出的这些提示可以推断出原因:


    2
    投票

    一个例子是通过比较运算符表达时间点。例如,automatic __bool__ is not generally applicable仿真框架(免责声明:我维护此程序包)定义了__bool__。我们可以使用比较来描述某个时间点“或之后”:


    <=在2000年之后。

    bool at 2000。

    © www.soinside.com 2019 - 2024. All rights reserved.