The last element in Python list is corrupted using Python C API

  c++, python, python-2.7

I have a graph class in C++, and I am trying to use the Python C API, so I can use matplotlib for plotting. However, after I call python modules from my C++ class with a list as input, the last element of the list is always messed up (I don’t know if corrupted is the proper term).

The class is large, so I will try to include the related parts of code in a minimal example. I convert a std::vector to a Python list object using these functions:

CPyObject stlVectorToPythonList_Long(std::vector<int> input) {
    CPyObject pList, pVal;
    pList = PyList_New(input.size());

    for(int i=0; i<input.size(); i++) {
      pVal = PyLong_FromLong(input[i]);
      PyList_SetItem(pList, i, pVal);
    }

    pList.AddRef();
    return pList;
}

CPyObject stlVectorToPythonList_Double(std::vector<double> input) {
  CPyObject pList, pVal;
  pList = PyList_New(input.size());

  for(int i=0; i<input.size(); i++) {
    pVal = PyFloat_FromDouble(input[i]);
    PyList_SetItem(pList, i, pVal);
  }

  pList.AddRef();
  return pList;
}

I call the Python function using the following code:

int main( int argc, char** argv )
{
  CPyInstance cpy_instance_;

  std::vector<int> X = {0,1,2,3,4};
  std::vector<int> Y = {5,6,7,8,9};
  std::vector<int> index_i = {0,1,2,3,4};
  std::vector<int> index_j=  {4,3,2,1,0};

  CPyObject pName = PyString_FromString("MyModule");
  CPyObject pModule = PyImport_Import(pName);

  CPyObject pArgs = PyTuple_New(4);      

  CPyObject pObj;
  pObj = stlVectorToPythonList_Long(X);
  PyTuple_SetItem(pArgs, 0, pObj);
  pObj = stlVectorToPythonList_Long(Y);
  PyTuple_SetItem(pArgs, 1, pObj);
  pObj = stlVectorToPythonList_Long(index_i);
  PyTuple_SetItem(pArgs, 2, pObj);
  pObj = stlVectorToPythonList_Long(index_j);
  PyTuple_SetItem(pArgs, 3, pObj);

  if(pModule) {
    CPyObject pFunc = PyObject_GetAttrString(pModule, "MyFunction");
    if(pFunc && PyCallable_Check(pFunc)) {
      CPyObject pRetValue = PyObject_CallObject(pFunc, pArgs);
    }
    else {
      std::cout << "ERROR: Calling MyFunction()n";
      return 0;
    }
    }
    else {
    std::cout << "ERROR: Module not imported" << std::endl;
    return 0;
  }


  std::cout << "Terminating..." << std::endl;
  return 0;
}

And, this is the python script:

#!/usr/bin/env python

import matplotlib.pyplot as plt
import numpy as np

def MyFunction(x, y, i, j): 
  print("x",str(x))
  print("y",str(y))
  print("i",str(i))
  print("j",str(j))

This is the output:

('x', '[0L, 1L, 2L, 3L, 5L]')
('y', '[5L, 6L, 7L, 8L, 0L]')
('i', '[0L, 1L, 2L, 3L, 4L]')
('j', '[4L, 3L, 2L, 1L, 1L]')

The last element of each list is wrong (except for the list for ‘i’). Also, if I change my data type of X and Y from int to double and use stlVectorToPythonList_Double instead of stlVectorToPythonList_Long, I get a segfault when calling MyFunction. What is going on here? I can’t find the issue.

Edit: Also, I am using the CPyObject and CPyInstance as discussed here. I will copy the class below for reference.

class CPyInstance {
  public:
    CPyInstance() {
      Py_Initialize();

    ~CPyInstance() {
      Py_Finalize();
    }
};


class CPyObject
{
private:
  PyObject *p;
public:
  CPyObject() : p(NULL) {}

  CPyObject(PyObject* _p) : p(_p) {}

  ~CPyObject() {
    Release();
  }

  PyObject* getObject() {
    return p;
  }

  PyObject* setObject(PyObject* _p) {
    return (p=_p);
  }

  PyObject* AddRef() {
    if(p)
    {
      Py_INCREF(p);
    }
    return p;
  }

  void Release() {
    if(p) {
      Py_DECREF(p);
    }

    p= NULL;
  }

  PyObject* operator ->() {
    return p;
  }

  bool is() {
    return p ? true : false;
  }

  operator PyObject*() {
    return p;
  }

  PyObject* operator = (PyObject* pp) {
    p = pp;
    return p;
  }

  operator bool() {
    return p ? true : false;
  }

};

Source: Windows Questions C++

LEAVE A COMMENT