Jessie K
Jessie K

Reputation: 93

Unpacking iterable in Python extension

I'm trying to translate a, b, c, d = iterable to Python's C/API.

I'm looking for a function similar to PyArg_ParseTuple, just for iterables.

In other words, something in the area of PyIter_Parse or PyObject_ParseIterable, if such functions would have existed.

Any tips how to implement it?

Upvotes: 1

Views: 331

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1124238

No, there is no helper function that can do this for you.

You'd have to use PyIter_Next() up to max times to retrieve values, raise an exception when you can't get at least min values, and then just build a tuple from that.

Something like (untested, largely pilfered from PySequence_Tuple()):

int
PyIter_LimitedTuple(PyObject *v, Py_ssize_t min, Py_ssize_t max)
{
    PyObject *it;  /* iter(v) */
    PyObject *result = NULL;
    Py_ssize_t j;

    it = PyObject_GetIter(v);
    if (it == NULL)
        return NULL;

    /* allocate space. */
    result = PyTuple_New(max);
    if (result == NULL)
        goto Fail;

    /* Fill the tuple. */
    for (j = 0; ; ++j) {
        PyObject *item = PyIter_Next(it);
        if (item == NULL) {
            if (PyErr_Occurred())
                goto Fail;
            break;
        }

        if (j > max) {
            PyErr_Format(PyExc_ValueError,
                "too many values to unpack");
            goto Fail;
        }

        PyTuple_SET_ITEM(result, j, item);
    }

    if (j < min) {
        PyErr_Format(PyExc_ValueError,
            "need more than %d value to unpack",
            j);
        goto Fail;
    }

    /* Cut tuple back if fewer than max items were available. */
    if (j < max &&
        _PyTuple_Resize(&result, j) != 0)
        goto Fail;

    Py_DECREF(it);
    return result; 

Fail:
    Py_XDECREF(result);
    Py_DECREF(it);
    return NULL;
}

then pass the resulting tuple to PyArg_UnpackTuple().

Upvotes: 2

Related Questions