使用 C 对象指针构建 PyObject*
Build a PyObject* with a C Object pointer
假设我有这个结构:
typedef struct
{
PyObject_HEAD
Foo* myFoo;
} PyFoo;
假设 Foo
是:
class Foo
{
public:
hello()
{
std::cout << "Hello\n";
}
};
我不想将 class Foo 重新制作为 python 模块,因为它代表了库中的一个 class,具有更多的函数和变量(但那不是'与这个问题无关)。我并没有真正从文档中理解如何在 C/C++ 中创建带有参数的 PyObject*,更不用说如何使用 C/C++ 指针作为参数了。
我要离开这个指南:https://docs.python.org/3/extending/newtypes_tutorial.html
我确实有指南中的 dealloc、new 和 init 方法,但我没有尝试初始化和解除分配任何值,对象本身的实例除外。
这个问题类似于Build a PyObject* from a C function? but I want to pass an object pointer instead of a function. I am using the same method as Create an object using Python's C API创建对象,但我不知道如何将 foo 的实例提供给 PyObject。
所以你可以使用胶囊来做到这一点。
创建对象时:
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。
然后我在 'new' 函数中使用了胶囊。
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;
}
我认为尝试使用指针调用构造函数会使事情变得比需要的更复杂。您的 tp_new
和 tp_init
方法旨在提供一个 Python 接口来创建对象实例。如果提供 Python 接口没有意义(例如,如果您的对象必须始终使用 C++ 指针创建)那么就不要提供它们 - 将它们设置为 NULL
和您的无法从 Python.
创建对象
在 C++ 中,您不受此接口的限制。您可以定义自己的 "C++ factory function" 并采用您喜欢的任何参数:
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 胶囊的厌恶。很难看到它们的合理用例,但人们还是喜欢使用它们。
假设我有这个结构:
typedef struct
{
PyObject_HEAD
Foo* myFoo;
} PyFoo;
假设 Foo
是:
class Foo
{
public:
hello()
{
std::cout << "Hello\n";
}
};
我不想将 class Foo 重新制作为 python 模块,因为它代表了库中的一个 class,具有更多的函数和变量(但那不是'与这个问题无关)。我并没有真正从文档中理解如何在 C/C++ 中创建带有参数的 PyObject*,更不用说如何使用 C/C++ 指针作为参数了。
我要离开这个指南:https://docs.python.org/3/extending/newtypes_tutorial.html
我确实有指南中的 dealloc、new 和 init 方法,但我没有尝试初始化和解除分配任何值,对象本身的实例除外。
这个问题类似于Build a PyObject* from a C function? but I want to pass an object pointer instead of a function. I am using the same method as Create an object using Python's C API创建对象,但我不知道如何将 foo 的实例提供给 PyObject。
所以你可以使用胶囊来做到这一点。
创建对象时:
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。
然后我在 'new' 函数中使用了胶囊。
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;
}
我认为尝试使用指针调用构造函数会使事情变得比需要的更复杂。您的 tp_new
和 tp_init
方法旨在提供一个 Python 接口来创建对象实例。如果提供 Python 接口没有意义(例如,如果您的对象必须始终使用 C++ 指针创建)那么就不要提供它们 - 将它们设置为 NULL
和您的无法从 Python.
在 C++ 中,您不受此接口的限制。您可以定义自己的 "C++ factory function" 并采用您喜欢的任何参数:
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 胶囊的厌恶。很难看到它们的合理用例,但人们还是喜欢使用它们。