【问题标题】:Build a PyObject* with a C Object pointer使用 C 对象指针构建 PyObject*
【发布时间】:2020-02-28 16:42:22
【问题描述】:

假设我有这个结构:

typedef struct
{
  PyObject_HEAD
  Foo* myFoo;
} PyFoo;

假设Foo 是:

class Foo
{
public:
  hello()
  {
    std::cout << "Hello\n";
  }
};

我不想将类 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。

【问题讨论】:

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


    【解决方案1】:

    我认为你让事情变得比试图用指针调用构造函数更复杂。您的 tp_newtp_init 方法旨在提供 Python 接口来创建对象实例。如果提供 Python 接口没有意义(例如,如果您的对象必须始终使用 C++ 指针创建),那么干脆不提供它们 - 将它们设置为 NULL 并且您的对象将无法从蟒蛇。

    在 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 胶囊的厌恶。很少看到对它们有意义的用例,但人们还是喜欢使用它们。

    【讨论】:

      【解决方案2】:

      所以你可以使用胶囊来做到这一点。

      创建对象时:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-03-07
        • 2011-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-01
        相关资源
        最近更新 更多