2

正如消息主题所说:我如何在 C/C++ 扩展模块中创建在 Python 代码中定义的类的新实例?我将在下面提供更多信息。

注意#1:我正在尝试使用 Python/C API 来执行此操作,如下所示。但是我也可以接受任何其他替代解决方案~)

我有一个 Python 文件,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()

在“ readAll ”函数中,我想将存储在 C/C++ 模块中的列表读回 Python 代码,然后打印每个元素。

预计从 CppProxy 返回的“dataList”是一个包含 RealTimeData 类元素的列表(如开头所定义的)。

为此,我认为在我的 C/C++ 模块扩展代码中,我需要创建一个 PyList 实例,然后创建一些 RealTimeData 实例。可能是这样的:

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);
}

我读了这个 SO 问题。我是否需要做与定义新的 PyTypeObject 相同的事情来描述 Python 类 RealTimeData,然后创建它的新实例?

但我认为这实际上是从 C++ 代码中引入了一种新的类类型,而不是重新使用已经在 Python 代码中定义的类类型。

任何帮助表示赞赏!

4

1 回答 1

4

Python 定义的类在 Python/C 扩展中实例化,与在 Python 中完全相同:通过导入它并调用类对象:

// 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;
    ...
}

几个不相关的注释:

  • 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.
  • Error checking is missing: the code doesn't check the result of 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.
于 2013-04-19T06:21:54.933 回答