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
呼び出しが必要です。