如何通过调用Python中的方法sort()来调用和处理方法__lt__



执行此代码:

class Person(object):
    def __init__(self, name):
        self.name = name
        try:
            lastBlank = name.rindex(' ')
            self.lastName = name[lastBlank+1:]
        except:
            self.lastName = name
    def __lt__(self, other):
        if self.lastName == other.lastName:
            return self.name < other.name
        return self.lastName < other.lastName
    def __str__(self):
        return self.name
me = Person('Michael Guttag')
him = Person('Barack Hussein Obama')
her = Person('Madonna')
pList = [me, him, her]
pList.sort() #invoke __lt__()
for p in pList:
    print p

并输出:

Michael Guttag
Madonna
Barack Hussein Obama

在这本书中,它举例说明了类和运算符重载(或多态性),它说:除了提供编写使用<的中缀表达式的语法便利外,这种重载还提供了对使用__lt__定义的任何多态方法的自动访问。内置的方法sort就是这样一种方法。因此,例如,如果pList是由类型为Person的元素组成的列表,则调用pList.sort()将使用类Person中定义的__lt__方法对该列表进行排序。

我不明白sort()是如何产生多态性的(实际上,经过大量研究,多态性的概念我还不清楚),也不知道__lt__是如何进行排序以给出这样的输出的。我需要一个循序渐进的指导。非常感谢。

丰富的比较方法__lt____le____gt____ge____eq__实现了各种比较操作。它们都比较两个对象(其中一个是self)。它们一起可以让你回答诸如"在这两个对象中,如果有一个,哪个更大"之类的问题?有很多排序算法可以让你列出一个对象列表,如果你能在每一对对象上回答这样的问题,你就可以把整个列表按正确的顺序排列。例如,一种更容易理解的方法被称为选择排序——它的工作原理是:

  1. 比较前两项。取最小的(如果相等,则选择第一个),称之为s
  2. s与您尚未检查的下一个项目进行比较,如果该项目较小,则它现在是s(否则,s仍然是旧的s
  3. 重复执行步骤2,直到您没有更多未检查的项目为止。这意味着s现在是您列表中最小的项目
  4. s移到列表的开头,将所有其他内容上移以填补s所在的"空白"
  5. 考虑列表的其余(即,排除第一项),并在此基础上运行整个过程
  6. 继续——排除前两个,然后是前三个,以此类推——直到剩下的列表只有一个项目。现在对整个列表进行排序

Python的list.sort方法运行一种更复杂但更快的算法,称为Timsort。它实现了同样的目的:假设你可以知道任何两个元素是如何相对于彼此排序的,它会为你对整个列表进行排序。

Timsort如何工作的细节并不重要——使用现有方法而不是编写自己的方法的意义在于,你可以相信它确实有效。重要的一点是,文档中没有任何地方可以保证它将使用<来比较每对元素-最好至少实现__eq__,这样sort就可以知道两个Person是否恰好相等。你可以这样写:

def __eq__(self, other):
    return self.name == other.name

一旦你做到了这一点,就有一个名为functools.total_ordering的内置魔术,它可以为你填充所有剩余的比较方法。你可以这样使用它:

import functools
@functools.total_ordering
class Person:
    ....

最新更新