Ключевая функция выполняется только один раз за значение, для производства пары (keyvalue, value)
; это затем используется для сортировки, а затем только значения возвращаются в отсортированном порядке. Это иногда называют Schwartzian transform.
Вы можете проверить это самостоятельно; вы могли бы рассчитывать, как часто функция вызывается, например:
>>> def keyfunc(value):
... keyfunc.count += 1
... return value
...
>>> keyfunc.count = 0
>>> sorted([0, 8, 1, 6, 4, 5, 3, 7, 9, 2], key=keyfunc)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> keyfunc.count
10
или вы могли бы собрать все ценности, которые в настоящее время передаются в; вы увидите, что они следуют за оригинальный порядок ввода:
>>> def keyfunc(value):
... keyfunc.arguments.append(value)
... return value
...
>>> keyfunc.arguments = []
>>> sorted([0, 8, 1, 6, 4, 5, 3, 7, 9, 2], key=keyfunc)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> keyfunc.arguments
[0, 8, 1, 6, 4, 5, 3, 7, 9, 2]
Если вы хотите, чтобы читать исходный код CPython, соответствующая функция называется listsort()
и keyfunc
используется в следующем цикле (saved_ob_item
является входом массив), который выполняется до сортировки происходит:
for (i = 0; i < saved_ob_size ; i++) {
keys[i] = PyObject_CallFunctionObjArgs(keyfunc, saved_ob_item[i],
NULL);
if (keys[i] == NULL) {
for (i=i-1 ; i>=0 ; i--)
Py_DECREF(keys[i]);
if (saved_ob_size >= MERGESTATE_TEMP_SIZE/2)
PyMem_FREE(keys);
goto keyfunc_fail;
}
}
lo.keys = keys;
lo.values = saved_ob_item;
так, в конце концов, у вас есть два массива, один с keys
и один с исходными значениями. Все операции сортировки действуют на два массива параллельно, сортируя значения в lo.keys
и перемещая элементы в lo.values
в тандеме.
Весь * point * of 'key =' против старшего 'cmp =' должен был сократить количество запросов для повышения производительности. Если он каждый раз выполнял вычисления, это было бы больше * вызовов функций, чем замененный 'cmp' подход, поэтому он не смог бы преуспеть в своей цели дизайна. –