如果你看一下 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
调用。