Python中与Java的compareTo()方法相对应的函数是什么?

19

我正在用Python (3.2)做一个项目,需要比较用户定义对象。我习惯于Java中的面向对象编程,在那里可以在类中定义一个compareTo()方法来指定该类的自然排序,如下例所示:

public class Foo {
    int a, b;

    public Foo(int aa, int bb) {
        a = aa;
        b = bb;
    }

    public int compareTo(Foo that) {
        // return a negative number if this < that
        // return 0 if this == that
        // return a positive number if this > that

        if (this.a == that.a) return this.b - that.b;
        else return this.a - that.a;
    }
}

我对Python中的类/对象比较陌生,所以我想知道定义类的自然排序的“Pythonic”方式是什么?


1
你的意思是像__cmp__这样吗? - Jeff Mercado
2个回答

26
你可以实现特殊方法__lt____gt__等来为自定义类型实现默认运算符。有关它们的详细信息,请参见语言参考手册
例如:
class Foo:
    def __init__ (self, a, b):
        self.a = a
        self.b = b

    def __lt__ (self, other):
        if self.a == other.a:
            return self.b < other.b
        return self.a < other.b

    def __gt__ (self, other):
        return other.__lt__(self)

    def __eq__ (self, other):
        return self.a == other.b and self.b == other.b

    def __ne__ (self, other):
        return not self.__eq__(other)

或者像stranac在评论中所说的那样,您可以使用total_ordering装饰器来节省一些打字:

@functools.total_ordering
class Foo:
    def __init__ (self, a, b):
        self.a = a
        self.b = b

    def __lt__ (self, other):
        if self.a == other.a:
            return self.b < other.b
        return self.a < other.b

    def __eq__ (self, other):
        return self.a == other.b and self.b == other.b

3
你可以定义 __lt____eq__ 并使用 functools.total_ordering 装饰器。该装饰器可以帮助你实现完整的比较运算符。 - stranac
1
在 Python 2 中,如果未提供 __gt__,则其自动为 not __lt__(我刚刚测试了一下)。奇怪的是文档中说得不一样。有人想在 Python 3 上测试一下吗,也许是@stranac? - schlamar
你说得对,但文档可能只是指反向操作,即 not (a < b) == (a >= b)(如果未定义,则后者会引发异常),所以我猜它会尽可能地交换参数。 - poke
@ms4py:我猜文档只是在说,如果__gt__False,并不一定意味着__lt__True。它们可以被定义为两者都为True/False的方式。 - stranac

7

Python有一个类似的函数:__cmp__()

我现在看到你在问关于Python 3的问题。他们的“新特性”建议

cmp()函数应被视为已删除,不再支持__cmp__()特殊方法。
使用__lt__()进行排序,使用__eq__()与__hash__()一起使用,
并根据需要使用其他丰富的比较。(如果您真的需要cmp()功能,
可以使用表达式(a > b) - (a < b)作为cmp(a, b)的等效形式。)

因此,看起来你总是可以做一些像这样的事情:

def compareTo(self, that):
    return ((self > that) - (self < that))

或者

@classmethod
def compare(cls, a, b):
    return ((a > b) - (a < b))

在实现 __gt__()__lt__() 之后,您可以像这样使用它们:

例如:

f1 = Foo(1,1)
f2 = Foo(2,2)

f1.compareTo(f2)
Foo.compare(f1,f2)

这将给您相同的功能。

5
在Python 3中,__cmp__方法已经不存在了。OP正在询问Python 3相关的内容。 - poke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接