在C++中通过继承自定义PyObject

Custom PyObject by inheritance in C++

本文关键字:继承 自定义 PyObject C++      更新时间:2023-10-16

长期python程序员,第一次编写C++扩展程序。无论如何,为了好玩,我正在尝试用C++为python创建一个链表模块。这是我的代码

#include <python2.7/Python.h>
#include <iostream>
using namespace std;
template <typename T>
class LinkedList : public PyObject {
private:
  struct ListNode {
    ListNode(T value, ListNode* next)
      : value(value), next(next) {}
    T value;
    ListNode* next;
  };
  ListNode* head;
public:
  LinkedList(T value)
    : head(new ListNode(value, 0)) {
    cout << "class constructed" << endl;
    Py_INCREF(this);
  }
  void get_value() {
    cout << "test" << endl;
  }
  ~LinkedList() {
    delete head;
    Py_DECREF(this);
    cout << "class destructed" << endl;
  }
};
static PyObject* linkedlist_new(PyObject* self, PyObject* args) {
  LinkedList<char*> ll("hello");
  return Py_BuildValue("O", &ll);
}
static PyMethodDef LinkedListMethods[] = {
    {"new", linkedlist_new, METH_VARARGS,
     "Create a new linked list."},
    {NULL, NULL, 0, NULL}
};
extern "C" PyMODINIT_FUNC initLinkedList(void) {
  (void) Py_InitModule("LinkedList", LinkedListMethods);
}

我能做这个吗?大多数文档都是针对C的,但我可以从PyObject继承并像这样返回吗?现在有效的是:

import LinkedList
print "start"
l = LinkedList.new()
print "done"

但当我在python中调用l.get_value()时,我会得到一个segfault。我知道我所做的可能是错误的,所以有人会好心地为我指明正确的方向吗?

为了澄清,我知道名为"ll"的LinkedList<char*>linkedlist_new函数完成后被破坏,这是我遇到的问题的一部分。让我们假设我非常非常失落。。。

首先:您可能需要手动设置对象标头——换句话说,更改

template <typename T>
class LinkedList : public PyObject { /* … */ }

类似

template <typename T>
class LinkedList {
    public:
        PyObject_HEAD
        /// …
}

…根据我自己的经验,如果Python对象的API的其余部分正确填充,则后一种方法有效。这是第二点:你没有定义PyTypeObject,它有点复杂(q.v。https://docs.python.org/2/c-api/typeobj.html)比你在这里拥有的还要多。

具体来说,您需要一个PyTypeObject,它对应于您打算向用户公开的每个PyObject派生的结构,因此,尽管模板化的PyObject派生的LinkedList类一开始听起来可能很棒,记住PyTypeObject结构(因为面向用户的模块表示不可避免地必须具体定义其中的一个或多个),以及LinkList最终专用的typename参数。