访问PyObject的底层结构体

3 投票
1 回答
3552 浏览
提问于 2025-04-16 02:30

我正在创建一个Python的C扩展,但在寻找相关文档时遇到了困难。我基本上想创建一个指向C结构的指针,并能够访问这个指针。下面是示例代码。任何帮助都将不胜感激。

typedef struct{
 int x;
 int y;
} Point;

typedef struct {
 PyObject_HEAD
 Point* my_point;
} PointObject;

static PyTypeObject PointType = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "point",             /*tp_name*/
    sizeof(PointObject), /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    0,                         /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT,        /*tp_flags*/
    "point objects",           /* tp_doc */
};

static PyObject* set_point(PyObject* self, PyObject* args)
{
 PyObject* point; 

 if (!PyArg_ParseTuple(args, "O", &point))
 {
  return NULL;
 }

    //code to access my_point    
}

1 个回答

3

你的 PyArg_ParseTuple 不应该使用格式 O,而应该用 O!(具体可以参考文档):

O! (object) [typeobject, PyObject *]

这个格式是用来在C语言中存储一个Python对象的指针。它和 O 类似,但需要两个C语言参数:第一个是Python类型对象的地址,第二个是一个C语言变量的地址(类型是 PyObject*),这个变量用来存储对象指针。如果传入的Python对象类型不对,就会抛出一个类型错误(TypeError)。

一旦你这样做了,你就可以确定在你函数的主体中,(PointObject*)point 会是一个正确有效的指向 PointObject 的指针,因此它的 ->my_point 就是你想要的 Point*。如果用普通的格式 O,你就得自己检查类型了。

编辑:提问者在评论中询问源代码...:

static PyObject*
set_point(PyObject* self, PyObject* args)
{
    PyObject* point; 

    if (!PyArg_ParseTuple(args, "O!", &PointType, &point))
    {
        return NULL;
    }

    Point* pp = ((PointObject*)point)->my_point;

    // ... use pp as the pointer to Point you were looking for...

    // ... and incidentally don't forget to return a properly incref'd
    // PyObject*, of course;-)
}

撰写回答