Ответ 1
Если вы посмотрите на байт-код python, становится очень очевидно, почему распаковка выполняется быстрее:
>>> import dis
>>> def unpack_or_index(t=(0, 1)):
... _, x = t
... x = t[1]
...
>>> dis.dis(unpack_or_index)
2 0 LOAD_FAST 0 (t)
3 UNPACK_SEQUENCE 2
6 STORE_FAST 1 (_)
9 STORE_FAST 2 (x)
3 12 LOAD_FAST 0 (t)
15 LOAD_CONST 1 (1)
18 BINARY_SUBSCR
19 STORE_FAST 2 (x)
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
Операция распаковки кортежей - простой байт-код (UNPACK_SEQUENCE
), а операция индексирования должна вызывать метод на кортеже (BINARY_SUBSCR
). Операция распаковки может выполняться внутри строки в цикле оценки python, в то время как для вызова подписки требуется поиск функции на объекте кортежа для получения значения с помощью PyObject_GetItem
.
UNPACK_SEQUENCE
код кода операции специальные фрагменты кортежей python или список распаковки, где длина последовательности точно соответствует длине аргумента:
if (PyTuple_CheckExact(v) &&
PyTuple_GET_SIZE(v) == oparg) {
PyObject **items = \
((PyTupleObject *)v)->ob_item;
while (oparg--) {
w = items[oparg];
Py_INCREF(w);
PUSH(w);
}
Py_DECREF(v);
continue;
} // followed by an "else if" statement for a list with similar code
Вышеприведенный код попадает в нативную структуру кортежа и напрямую извлекает значения; нет необходимости использовать тяжелые вызовы, такие как PyObject_GetItem
, которые должны учитывать, что объект может быть обычным классом python.
Операционный код BINARY_SUBSCR
оптимизирован только для списков python; все, что не является родным списком python, требует вызова PyObject_GetItem
.