使用C对象指针构建PyObject *

时间:2019-11-02 20:58:01

标签: python c++ cpython python-c-api

说我有这个结构:

g

我们只说g是:

Class

我不想将Foo类重新制成python模块,因为它表示库中具有更多函数和变量的类(但这与该问题无关)。我从文档中并没有真正理解如何在C / C ++中创建带有参数的PyObject *,更不用说如何使用C / C ++指针作为参数了。

我要退出本指南:https://docs.python.org/3/extending/newtypes_tutorial.html

我确实有本指南中的dealloc,new和init方法,但除对象本身的实例外,我没有尝试初始化和释放任何值。

这个问题类似于Build a PyObject* from a C function?,但我想传递对象指针而不是函数。我正在使用与Create an object using Python's C API相同的方法来创建对象,但是我不知道如何将foo的实例提供给PyObject。

2 个答案:

答案 0 :(得分:2)

我认为您正在使事情变得比试图用指针调用构造函数更为复杂。您的tp_newtp_init方法旨在为创建对象实例提供Python接口。如果提供Python接口没有意义(例如,如果必须始终使用C ++指针创建对象),则只需不提供它们-将它们设置为NULL,则不会可通过Python创建。

在C ++中,您不受此接口的限制。您可以根据自己的喜好定义自己的“ C ++工厂函数”:

PyFoo* make_PyFoo(Foo* myfoo) {

首先分配对象:

PyFoo *obj = (PyFoo*)(type->tp_alloc(type, 0));
# or
PyFoo *obj = PyObject_New(PyFoo, type); # use PyObject_GC_new if it has cyclic references

如果您尚未定义自定义分配器,则这两种方法几乎等效。这里省略了一些错误检查。...

接下来,您可以简单地使用现有的Foo*指针来初始化相关字段:

obj->myfoo = myfoo;

然后仅return obj(并合上括号)。


这个答案在很大程度上是由于我长期以来对Python胶囊的厌恶。很难看到适合他们的用例,但是人们还是喜欢使用它们。

答案 1 :(得分:0)

因此您可以使用胶囊来做到这一点。

创建对象时:

Foo* myFoo = new Foo();
PyObject* capsule = PyCapsule_New((void*) myFoo, "Foo", NULL);
PyObject* argList = Py_BuildValue("(O)", capsule);
PyObject *obj = PyObject_CallObject((PyObject*) &Foo_PyTypeObject, argList);
Py_DECREF(arglist);
Py_DECREF(capsule); // I don't need python to keep the reference to myFoo

Foo_PyTypeObject应该是您为扩展对象创建的PyTypeObject。

然后我在“新”功能中使用了胶囊。

Foo_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
{
  Foo* self;
  self = (Foo*) type->tp_alloc(type, 0);
  if (self != NULL)
  {
    static char *kwlist[] = {const_cast<char*>("Foo"), NULL};

    PyObject* capsule = NULL;
    PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &capsule);
    self->myFoo = (Foo*) PyCapsule_GetPointer(capsule, "Foo"); // this is the myFoo in the PyFoo struct
    Py_DECREF(capsule);
  }
  return (PyObject*) self;
}