-
Notifications
You must be signed in to change notification settings - Fork 1
Description
@sergey-miryanov analyzed the Python code base for tuple creation and identified that the most common tuple sizes are 1 and 2 items. He proposes adding PyTuple_MakeSingle() and PyTuple_MakePair() functions as the new way to create these tuples.
There are already other ways to build tuples of arbitrary size:
PyTuple_New()+PyTuple_SET_ITEM()PyTuple_New()+PyTuple_SetItem()PyTuple_Pack()PyTuple_FromArray()-- new in Python 3.15
Proposed functions are a little bit faster, but it's matter of nanoseconds: benchmark on Linux. Fastest to slowest method:
PyTuple_FromArray()--PyTuple_MakeSingle()orPyTuple_MakePair()-- similar performancePyTuple_Pack()PyTuple_New()+PyTuple_SET_ITEM()PyTuple_New()+PyTuple_SetItem()
The difference with PyTuple_FromArray() is that you don't have to create a temporary array on the stack to build the tuple.
PyObject *array[2] = {key, value};
return PyTuple_FromArray(array, 2);versus:
return PyTuple_MakePair(key, value);It's more convenient and natural to build a 2-tuple like that.
It's common to have to create strong references for items when building a new tuple. Example:
PyObject *key = new_key();
PyObject *value = new_value();
if (!key || !value) {
Py_XDECREF(key);
Py_XDECREF(value);
return NULL;
}
PyObject *tuple = PyTuple_MakePair(key, value);
Py_DECREF(key);
Py_DECREF(value);
return tuple;It was also proposed to add PyTuple_MakeSingleSteal() and PyTuple_MakePairSteal() variants which transfer the items ownership. The example becomes:
PyObject *key = new_key();
PyObject *value = new_value();
if (!key || !value) {
Py_XDECREF(key);
Py_XDECREF(value);
return NULL;
}
return PyTuple_MakePairSteal(key, value);Using Steal variant, the final DECREF is no longer needed. But these variants were put aside for now.
@kumaraditya303 added:
I would prefer to have only steal versions because there are less redundant reference counting operations. decrefs are expensive on hot paths and users can easily incref before passing to steal function as needed.
Considering that reference counting is more expensive on free-threading, I think we should encourage the use of Steal functions to avoid redundant reference counting operations.