简体   繁体   中英

How do I convert a 2d Python list to a 2d C++ vector?

I'm giving my function a 2d Python list and would like to convert it to a 2d C++ Vector. But I don't understand how I can do that. The input is a list of n-dimensional coordinate points. Each of these coordinate points is a list itself. The individual point values are doubles. This is my code so far:

PyObject* foo(PyObject* self, PyObject* args) {
    PyObject* polyList;
    // Verify that argument is a list
    if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &polyList)) {
        return NULL;
    }
    std::vector<std::vector<double>> poly;
    // for each elem in list
    for (unsigned int i = 0; i < PyList_Size(polyList); ++i) {
        PyObject* pypoint = PyList_GetItem(polyList, i);
        std::vector<double> point;
        // Verify that elem is a list (coord point)
        if (!PyArg_ParseTuple(pypoint, "O!", &PyList_Type, &pypoint)) {
            PyErr_SetString(PyExc_TypeError, "must pass in list of list");
            return NULL;
        }
        for (unsigned int j = 0; j < PyList_Size(pypoint); ++i) {
            PyObject* coord = PyList_GetItem(pypoint, j);
            double val;
            // Verify that coord is a double
            if (!PyArg_ParseTuple(coord, "d", &val)) {
                PyErr_SetString(PyExc_TypeError, "must pass in list of list of number");
                return NULL;
            }
            point.push_back(val);
        }
        poly.push_back(point);
    }
    //...
}

When I pass a 2d list like [[1.0, 1.0], [2.5, 3.7]] I get an Error saying, that I have to pass a list of lists. So I guess the error lies somewhere in line if (,PyArg_ParseTuple(pypoint, "O,", &PyList_Type, &pypoint)) { . But what is pypoint if not a list? Using cout << Py_TYPE(pypoint) I got 66577D20 but that doesn't tell me anything.

I read in another thread on here, that it could be because Python lists are lists of pointers, but that still doesn't tell me how to do the conversion.

Thanks to @YiFei I looked into PyList_Check and other Py_Check functions and found a working solution. Here is the code:

PyObject* foo(PyObject* self, PyObject* args) {
    PyObject* polyList;
    // Verify that argument is a list
    if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &polyList)) {
        return NULL;
    }
    std::vector<std::vector<double>> poly;
    for (int i = 0; i < PyList_Size(polyList); ++i) {
        PyObject* pypoint = PyList_GetItem(polyList, i);
        std::vector<double> point;
        // Verify that each pypoint also a list
        if (!PyList_Check(pypoint)) {
            PyErr_SetString(PyExc_TypeError, "must pass in list of list");
            return NULL;
        }
        for (int j = 0; j < PyList_Size(pypoint); ++j) {
            PyObject* coord = PyList_GetItem(pypoint, j);
            double val;
            // Check that each coord is a long/double
            if (PyLong_Check(coord)) {
                val = (double) PyLong_AsLong(coord);
            } else if (PyFloat_Check(coord)) {
                val = PyFloat_AsDouble(coord);
            } else {
                PyErr_SetString(PyExc_TypeError, "must pass in list of list of number");
                return NULL;
            }
            point.push_back(val);
        }
        poly.push_back(point);
    }
    //...
}

Of course the following lines can be substituted with any other check to convert a 2d list of non long/double values to a 2d vector.

// Check that each coord is a long/double
if (PyLong_Check(coord)) {
    val = (double) PyLong_AsLong(coord);
} else if (PyFloat_Check(coord)) {
    val = PyFloat_AsDouble(coord);
} else {
    PyErr_SetString(PyExc_TypeError, "must pass in list of list of number");
    return NULL;
}

See https://docs.python.org/3/c-api/concrete.html for the specific Py_Check function of the desired type.

It may not be the most optimized solution, but it works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM