Python 使用C对象指针构建PyObject*

Python 使用C对象指针构建PyObject*,python,c++,cpython,python-c-api,Python,C++,Cpython,Python C Api,假设我有这个结构: typedef struct { PyObject_HEAD Foo* myFoo; } PyFoo; 让我们假设Foo是: class Foo { public: hello() { std::cout << "Hello\n"; } }; class-Foo { 公众: 你好() { std::cout所以你可以用胶囊来做这件事 创建对象时: Foo* myFoo = new Foo(); PyObject* capsule =

假设我有这个结构:

typedef struct
{
  PyObject_HEAD
  Foo* myFoo;
} PyFoo;
让我们假设
Foo
是:

class Foo
{
public:
  hello()
  {
    std::cout << "Hello\n";
  }
};
class-Foo
{
公众:
你好()
{

std::cout所以你可以用胶囊来做这件事

创建对象时:

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;
}
Foo_new(PyTypeObject*type,PyObject*args,PyObject*kwds)
{
福*赛尔夫;
self=(Foo*)类型->tp_alloc(类型,0);
if(self!=NULL)
{
静态字符*kwlist[]={const_cast(“Foo”),NULL};
PyObject*capsule=NULL;
PyArg_ParseTupleAndKeywords(args、kwds、“O”、kwlist和capsule);
self->myFoo=(Foo*)PyCapsule\u GetPointer(capsule,“Foo”);//这是PyFoo结构中的myFoo
Py_DECREF(胶囊);
}
返回(PyObject*)self;
}

所以你可以用胶囊来做这件事

创建对象时:

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;
}
Foo_new(PyTypeObject*type,PyObject*args,PyObject*kwds)
{
福*赛尔夫;
self=(Foo*)类型->tp_alloc(类型,0);
if(self!=NULL)
{
静态字符*kwlist[]={const_cast(“Foo”),NULL};
PyObject*capsule=NULL;
PyArg_ParseTupleAndKeywords(args、kwds、“O”、kwlist和capsule);
self->myFoo=(Foo*)PyCapsule\u GetPointer(capsule,“Foo”);//这是PyFoo结构中的myFoo
Py_DECREF(胶囊);
}
返回(PyObject*)self;
}

我认为您试图用指针调用构造函数,这让事情变得比需要的更复杂。您的
tp_new
tp_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;
然后只需
返回obj
(并关闭支架)



这个答案很大程度上是受我长期以来对Python胶囊的厌恶所启发的。很少看到它们有合理的用例,但人们还是喜欢使用它们。

我认为你试图用指针调用构造函数会使事情变得比需要的更复杂。你的
tp_new
tp_init
方法已经过时了为提供对象实例提供Python接口。如果提供Python接口没有意义(例如,如果您的对象必须始终用C++指针创建),则不必提供它们-将它们设置为<代码> null < /C> >并且您的对象将不能从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;
然后只需
返回obj
(并关闭支架)


这个答案很大程度上是受我长期以来对Python胶囊的厌恶所启发的。很难看到它们的合理使用案例,但人们还是喜欢使用它们