Tuple in python is immutable by design, so if we try to mutate a tuple object, python emits following TypeError
which make sense.
>>> a = (1, 2, 3)
>>> a[0] = 12
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
So my question is, if tuple is immutable by design why cpython exposes PyTuple_SetItem
as C-API?.
From the documentation it's described as
int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o)
Insert a reference to object
o
at position pos of the tuple pointed to byp
. Return0
on success. Ifpos
is out of bounds, return-1
and set an IndexError exception.
Isn't this statement exactly equal to tuple[index] = value
in python layer?. If the goal was to create a tuple from collection of items we could have use PyTuple_Pack
.
Additional note:
After lot of trial and error with ctypes.pythonapi
I managed to mutate tuple object using PyTuple_SetItem
import ctypes
from ctypes import py_object
my_tuple = (1, 2, 3)
newObj = py_object(my_tuple)
m = "hello"
# I don't know why I need to Py_DecRef here.
# Although to reproduce this in your system, no of times you have
# to do `Py_DecRef` depends on no of ref count of `newObj` in your system.
ctypes.pythonapi.Py_DecRef(newObj)
ctypes.pythonapi.Py_DecRef(newObj)
ctypes.pythonapi.Py_DecRef(newObj)
ctypes.pythonapi.Py_IncRef(m)
PyTuple_SetItem = ctypes.pythonapi.PyTuple_SetItem
PyTuple_SetItem.argtypes = ctypes.py_object, ctypes.c_size_t, ctypes.py_object
PyTuple_SetItem(newObj, 0, m)
print(my_tuple) # this will print `('hello', 2, 3)`
PyTuple_Pack
is only usable in cases where the number of tuple elements is fixed. The only way to initialize a variable-sized tuple at the C level would be to callPyTuple_SetItem
in a loop. – Inman