gpt4 book ai didi

python - __lt__ 而不是 __cmp__

转载 作者:IT老高 更新时间:2023-10-28 21:08:36 26 4
gpt4 key购买 nike

Python 2.x 有两种重载比较运算符的方法, __cmp__ 或“丰富的比较运算符”,例如 __lt__ . 富比较重载据说是首选,但为什么会这样呢?

丰富的比较运算符实现起来更简单,但您必须使用几乎相同的逻辑来实现其中的几个。但是,如果您可以使用内置 cmp和元组排序,然后 __cmp__变得非常简单并满足所有比较:

class A(object):
def __init__(self, name, age, other):
self.name = name
self.age = age
self.other = other
def __cmp__(self, other):
assert isinstance(other, A) # assumption for this example
return cmp((self.name, self.age, self.other),
(other.name, other.age, other.other))

这种简单性似乎比重载所有 6(!) 个丰富的比较更能满足我的需求。 (但是,如果您依赖“交换的参数”/反射(reflect)的行为,您可以将其降低到“仅”4,但在我看来,这会导致并发症的净增加。)

如果我只重载__cmp__,是否需要注意任何不可预见的陷阱? ?

我了解 < , <= , ==等运算符可以被重载用于其他目的,并且可以返回他们喜欢的任何对象。我不是在问这种方法的优点,而只是在使用这些运算符进行比较时的差异,就像它们对数字的意义一样。

更新: 作为 Christopher pointed out , cmp在 3.x 中消失。 是否有任何替代方法可以像上面那样简单地实现比较 __cmp__ ?

最佳答案

是的,实现一切都很容易,例如__lt__带有一个 mixin 类(或者一个元类,或者一个类装饰器,如果你喜欢这样的话)。

例如:

class ComparableMixin:
def __eq__(self, other):
return not self<other and not other<self
def __ne__(self, other):
return self<other or other<self
def __gt__(self, other):
return other<self
def __ge__(self, other):
return not self<other
def __le__(self, other):
return not other<self

现在您的类(class)可以只定义 __lt__并从 ComparableMixin 乘以继承(在它需要的任何其他基础之后,如果有的话)。一个类装饰器会非常相似,只是插入类似的函数作为它正在装饰的新类的属性(结果在运行时可能会在微观上更快,在内存方面的成本同样微小)。

当然,如果您的类(class)有一些特别快速的实现方式(例如)__eq____ne__ ,它应该直接定义它们以便不使用 mixin 的版本(例如,dict 的情况)——实际上是 __ne__很可能将其定义为:

def __ne__(self, other):
return not self == other

但在上面的代码中,我想保持只使用 < 的令人愉悦的对称性。 ;-)。至于为什么__cmp__不得不去,因为我们确实__lt__和 friend 们,为什么要使用另一种不同的方式来做同样的事情呢?在每个 Python 运行时(Classic、Jython、IronPython、PyPy ......)中,它都是如此沉重。 肯定不会有错误的代码是不存在的代码——Python 的原则是理想情况下应该有一种明显的方式来执行任务(C 在ISO 标准的“C 精神”部分,顺便说一句)。

这并不意味着我们会竭尽全力禁止某些事情(例如,在某些用途中,mixin 和类装饰器之间几乎等效),但它绝对确实意味着我们不喜欢在编译器和/或运行时中携带冗余存在的代码,只是为了支持多种等效方法来执行完全相同的任务。

进一步编辑:实际上有一种更好的方法可以为许多类提供比较和散列,包括问题中的那个——__key__方法,正如我在对该问题的评论中提到的那样。由于我从来没有为它编写 PEP,如果你喜欢它,你现在必须使用 Mixin (&c) 来实现它:

class KeyedMixin:
def __lt__(self, other):
return self.__key__() < other.__key__()
# and so on for other comparators, as above, plus:
def __hash__(self):
return hash(self.__key__())

将一个实例与其他实例的比较归结为将每个实例的一个元组与几个字段进行比较是一种非常常见的情况——然后,散列应该在完全相同的基础上实现。 __key__特殊方法地址直接需要。

关于python - __lt__ 而不是 __cmp__,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1061283/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com