""" python标准模块functools中的cmp_to_key可以将一个cmp函数变成一个key函数,从而支持自定义排序 python的列表提供了sort方法,下面是该方法的一个示例 """ lst = [(9, 4), (2, 10), (4, 3), (3, 6)] lst.sort(key=lambda item: item[0]) print(lst) """ sort方法的key参数需要设置一个函数,这个函数返回元素参与大小比较的值,这看起来没有问题,但如果想实现更加复杂的自定义排序,就不那么容易了。 目前的排序规则是根据元组里第一个元素的大小进行排序,我现在修改规则,如果元组里第一个元素是奇数,就用元组里第一个元素进行排序, 如果元组里第一个元素是偶数,则用这个元组里的第二个元组进行大小比较,面对这样的需求,列表的sort方法无法满足。 对于这种情形,可以使用functools.cmp_to_key来解决 """ from functools import cmp_to_key lst = [(9, 4), (2, 10), (4, 3), (3, 6)] def cmp(x, y): a = x[0] if x[0] % 2 == 1 else x[1] b = y[0] if y[0] % 2 == 1 else y[1] return 1 if a > b else -1 if a < b else 0 lst.sort(key=cmp_to_key(cmp)) print(lst) # 仍然使用sort进行排序,我实现了一个cmp函数,该函数实现了需求中所提到的要求,该函数最终要返回两个元组比较的大小关系,其实cmp_to_key的实现非常简单 def cmp_to_key(mycmp): """Convert a cmp= function into a key= function""" class K(object): __slots__ = ['obj'] def __init__(self, obj): self.obj = obj def __lt__(self, other): return mycmp(self.obj, other.obj) < 0 def __gt__(self, other): return mycmp(self.obj, other.obj) > 0 def __eq__(self, other): return mycmp(self.obj, other.obj) == 0 def __le__(self, other): return mycmp(self.obj, other.obj) <= 0 def __ge__(self, other): return mycmp(self.obj, other.obj) >= 0 __hash__ = None return K """ 它在内部定义了一个类K, 并使用我传入的cmp函数完成了比较关系运算符的重载,函数返回的是一个类,而sort函数的key需要的是一个函数, 看起来矛盾,但在python中,这样做完全可行,因为类和函数都是callable的,这里把类当成了函数来用。 在本篇第一段代码中 lst.sort(key=lambda item: item[0]) lambda表达式生成的匿名函数返回的是元组的第一个元素进行大小比较,而现在,cmp_to_key返回的是类K,参与比较的是K的对象, 由于K已经实现了比较关系运算符重载,且算法就是我刚刚实现的cmp函数,这样就最终实现了自定义排序。 """