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.