__lt__而不是__cmp__ [英] __lt__ instead of __cmp__

查看:101
本文介绍了__lt__而不是__cmp__的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Python 2.x has two ways to overload comparison operators, __cmp__ or the "rich comparison operators" such as __lt__. The rich comparison overloads are said to be preferred, but why is this so?

每个比较器都比较容易实现,但是您必须使用几乎相同的逻辑来实现其中的几个.但是,如果可以使用内置的cmp和元组排序,则__cmp__会变得非常简单并完成所有比较:

Rich comparison operators are simpler to implement each, but you must implement several of them with nearly identical logic. However, if you can use the builtin cmp and tuple ordering, then __cmp__ gets quite simple and fulfills all the comparisons:

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(!)比较更好地满足了我的需求. (但是,如果您依靠交换参数"/反映的行为,则可以将其降低到仅" 4,但是根据我的拙见,这会导致并发症的净增加.)

This simplicity seems to meet my needs much better than overloading all 6(!) of the rich comparisons. (However, you can get it down to "just" 4 if you rely on the "swapped argument"/reflected behavior, but that results in a net increase of complication, in my humble opinion.)

如果仅超载__cmp__,是否需要了解任何不可预见的陷阱?

Are there any unforeseen pitfalls I need to be made aware of if I only overload __cmp__?

我了解<<===等.运算符可以因其他目的而重载,并且可以返回他们喜欢的任何对象.我并不是在问这种方法的优点,而只是在询问使用这些运算符进行比较时的区别,就如同它们对数字的含义一样.

I understand the <, <=, ==, etc. operators can be overloaded for other purposes, and can return any object they like. I am not asking about the merits of that approach, but only about differences when using these operators for comparisons in the same sense that they mean for numbers.

更新:正如克里斯托弗指出的那样cmp在3.x版本中消失了. 是否有其他方法可以使进行比较的操作与上述__cmp__一样容易?

Update: As Christopher pointed out, cmp is disappearing in 3.x. Are there any alternatives that make implementing comparisons as easy as the above __cmp__?

推荐答案

是的,很容易实现所有方面,例如__lt__具有mixin类(或元类,或者,如果您的口味如此,则可以使用类装饰器).

Yep, it's easy to implement everything in terms of e.g. __lt__ with a mixin class (or a metaclass, or a class decorator if your taste runs that way).

例如:

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

现在,您的类可以只定义__lt__并从ComparableMixin中继承(在需要的其他基础之后,如果有的话).一个类装饰器将是非常相似的,只是插入与其装饰的新类的属性相似的函数(结果可能在运行时在微观上更快,而在内存方面的花费也同样小).

Now your class can define just __lt__ and multiply inherit from ComparableMixin (after whatever other bases it needs, if any). A class decorator would be quite similar, just inserting similar functions as attributes of the new class it's decorating (the result might be microscopically faster at runtime, at equally minute cost in terms of memory).

当然,如果您的班级有某种特别快的方法来实现(例如)__eq____ne__,则应直接定义它们,以便不使用mixin的版本(例如,)-实际上,__ne__可以很方便地定义为:

Of course, if your class has some particularly fast way to implement (e.g.) __eq__ and __ne__, it should define them directly so the mixin's versions are not use (for example, that is the case for dict) -- in fact __ne__ might well be defined to facilitate that as:

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

,但是在上面的代码中,我想保持仅使用< ;-)的令人愉悦的对称性. 至于为什么__cmp__必须去,因为我们 did __lt__和朋友,为什么还要用另一种不同的方法来做完全一样的事情呢?在每个Python运行时(经典,Jython,IronPython,PyPy等)中,它是如此沉重. 绝对不会有错误的代码是不存在的代码-从那里开始,Python的原理应该是一种理想的执行任务的方式(C的原理与ISO标准的"C的精神"部分,btw).

but in the code above I wanted to keep the pleasing symmetry of only using <;-). As to why __cmp__ had to go, since we did have __lt__ and friends, why keep another, different way to do exactly the same thing around? It's just so much dead-weight in every Python runtime (Classic, Jython, IronPython, PyPy, ...). The code that definitely won't have bugs is the code that isn't there -- whence Python's principle that there ought to be ideally one obvious way to perform a task (C has the same principle in the "Spirit of C" section of the ISO standard, btw).

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

This doesn't mean we go out of our way to prohibit things (e.g., near-equivalence between mixins and class decorators for some uses), but it definitely does mean that we don't like to carry around code in the compilers and/or runtimes that redundantly exists just to support multiple equivalent approaches to perform exactly the same task.

进一步的实际上,还有一种更好的方法可以为许多类提供比较和哈希,包括问题中的-__key__方法,正如我在对该问题的评论中提到的那样.由于我从来没有为它编写PEP,因此,如果愿意,您当前必须使用Mixin(& c)来实现它:

Further edit: there's actually an even better way to provide comparison AND hashing for many classes, including that in the question -- a __key__ method, as I mentioned on my comment to the question. Since I never got around to writing the PEP for it, you must currently implement it with a Mixin (&c) if you like it:

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__特殊方法直接解决了需要.

It's a very common case for an instance's comparisons with other instances to boil down to comparing a tuple for each with a few fields -- and then, hashing should be implemented on exactly the same basis. The __key__ special method addresses that need directly.

这篇关于__lt__而不是__cmp__的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆