As the message subject says: How can I, in the C/C++ extension module, create a new instance of a class that's defined in Python code? I'll provide more info below.
NOTE#1: I'm trying to do this with Python/C APIs, as you'll see below. But any other alternative solutions are also acceptable for me~)
I have a Python file, CppInterop.py:
import CppProxy
class RealTimeData:
def __init__(self, id, value):
self.id = id
self.value = value
def writeAll():
dataList= []
dataList.append(RealTimeData("ID::001", 1.0))
dataList.append(RealTimeData("ID::002", 2.0))
dataList.append(RealTimeData("ID::003", 3.0))
count = CppProxy.WriteRealTimeDataList(dataList)
print count
def readAll():
dataList = CppProxy.ReadRealTimeDataList() # Try to read the list back
for data in dataList:
print "id: ", data.id
print "value: ", data.value
pass
if __name__ == '__main__':
writeAll()
readAll()
In the "readAll" function I want to read the list stored in the C/C++ module back to Python code and then print every element.
It is expected the "dataList" returned from the CppProxy is a list that contains elements of class RealTimeData(as defined at the beginning).
To do so, I think in my C/C++ module extension code I need to create a PyList instance and then some instances of the RealTimeData. Might be something like this:
static
PyObject * ReadRealTimeDataList(PyObject * self, PyObject * args)
{
// Create a new Python list, size of which is zero.
PyObject * listObj = PyList_New(0);
if (NULL == listObj)
{
return NULL;
}
// Append some elements to the list
for (int i = 0; i < 3; ++i)
{
// How can I create a RealTimeData instance here and assign it to dataObj?
PyObject * dataObj;
PyObject * idObj = PyString_FromString("some id");
PyObject_SetAttrString(dataObj, "id", idObj);
PyObject * valueObj = PyFloat_FromDouble((double)i);
PyObject_SetAttrString(dataObj, "value", valueObj);
if (PyList_Append(listObj, dataObj) != 0)
{
// error!
return NULL;
}
}
// return the list object to Python part
return Py_BuildValue("O", listObj);
}
I read this SO question. Do I need to do the same stuff as defining a new PyTypeObject to describe the Python class RealTimeData, and then create new instances of it?
But I think this actually introduces a new class type from C++ code, not re-using a class type that's already defined in Python code.
Any help is appreciated!
A Python-defined class is instantiated in a Python/C extension exactly the same as in Python: by importing it and calling the class object:
// obtain the RealTimeData class
PyObject *get_RealTimeData()
{
PyObject *module = PyImport_ImportModule("CppInterop");
if (!module)
return NULL;
return PyObject_GetAttrString(module, "RealTimeData");
}
static
PyObject *ReadRealTimeDataList(PyObject *self, PyObject *args)
{
static PyObject *RealTimeData = get_RealTimeData();
...
// instantiate the class like you would in Python - by
// calling the class object
dataObj = PyObject_CallFunction(RealTimeData, "sd", "some id", 0.0);
if (!dataObj)
return NULL;
...
}
Several unrelated notes:
RealReadTimeDataList
for some reason doesn't return the data list, but a single-element tuple that holds the list. Since your Python code expects the list itself, just return listObj
instead.PyString_FromString
, PyFloat_FromDouble
, or PyObject_SetAttrString
.Py_DECREF(listObj)
should be called when PyList_Append
fails. As written, the code would leak listObj
in such a situation.