在Python中,
list.sort
方法和内置函数sorted
都可以接受一个可选参数key
,它是一个函数,给定列表中的一个元素返回其排序关键字。旧版本的Python使用了不同的方法,使用cmp
参数,它是一个函数,给定列表中的两个元素,如果第一个小于第二个则返回负数,如果相等则返回零,如果第一个大于第二个则返回正数。在某个时候,这个参数被弃用并且没有包含在Python 3中。有一天我想按照cmp
函数更容易编写的方式对元素列表进行排序。我不想使用废弃的特性,所以我阅读了文档,并发现有一个名为cmp_to_key
的函数存在于functools
模块中,正如其名称所示,它接收一个cmp
函数并返回一个key
函数... 或者至少在我阅读类似于源代码的高级函数所包含的文档中是这样的。def cmp_to_key(mycmp):
'Convert a cmp= function into a key= function'
class K(object):
def __init__(self, obj, *args):
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
def __ne__(self, other):
return mycmp(self.obj, other.obj) != 0
return K
尽管 cmp_to_key
能够按照预期工作,但我对这个函数返回的不是函数而是一个 K
类感到惊讶。为什么?它是如何工作的?我的猜测是 sorted
函数在内部检查 cmp 是否是函数或 K 类或类似的东西,但我不确定。
附言: 尽管有些奇怪,我发现 K 类非常有用。请查看以下代码:from functools import cmp_to_key
def my_cmp(a, b):
# some sorting comparison which is hard to express using a key function
class MyClass(cmp_to_key(my_cmp)):
...
这样,任何 MyClass 实例的列表都可以默认按照 my_cmp
中定义的标准进行排序。
key(a) < key(b)
。只要key
像可调用对象一样工作,那就没问题了。请参见https://en.wikipedia.org/wiki/Duck_typing。 - Justin Harrisclass MyClass(cmp_to_key(my_cmp)):
时,出现了TypeError: cannot create 'functools.KeyWrapper' instances
的错误。因此,我猜测这不是一种可靠的继承方式 - 似乎_functools
(C实现版本)不支持这样做。 - wim