Ответ 1
Метод cmp_to_key
возвращает специальный объект, который действует как суррогатный ключ:
class K(object):
__slots__ = ['obj']
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
def __hash__(self):
raise TypeError('hash not implemented')
При сортировке каждая клавиша будет сравниваться с большинством других клавиш в последовательности. Этот элемент находится в позиции 0 ниже или больше, чем этот другой объект?
Всякий раз, когда это происходит, вызываются специальные крючки метода, поэтому вызывается __lt__
или __gt__
, который вместо суррогатного ключа превращается в вызов метода cmp
.
Итак, список [1, 2, 3]
сортируется как [K(1), K(2), K(3)]
, а если, скажем, K(1)
сравнивается с K(2)
, чтобы увидеть, если K(1)
ниже, тогда вызывается K(1).__lt__(K(2))
, который переводится на mycmp(1, 2) < 0
.
Таким образом, старый метод cmp
работал; return -1, 0 или 1, в зависимости от того, первый аргумент ниже, равный или превышающий второй аргумент. Суррогатный ключ переводит эти числа обратно в логические значения для операторов сравнения.
Ни в коем случае суррогатный ключ не должен знать ничего об абсолютных позициях. Он должен знать только об одном другом объекте, с которым он сравнивается, и специальные крючки метода обеспечивают этот другой объект.