📜  Python| C 扩展模块中的不透明指针

📅  最后修改于: 2022-05-13 01:55:45.093000             🧑  作者: Mango

Python| C 扩展模块中的不透明指针

让我们讨论一个扩展模块,它需要处理指向 C 数据结构的指针,而不会将结构的任何内部细节暴露给Python。不透明的数据结构可以通过将它们包装在胶囊对象中来轻松处理,如下面的代码片段所示。

代码#1:

typedef struct Point
{
    double x, y;
} Point;
  
extern double distance(Point *p1, Point *p2);

参考上一篇文章找到 distance()函数——在Python中使用 C 代码。

代码 #2:给出的代码是一个扩展代码,它使用胶囊包装了Point结构和distance()函数。

/* Destructor function for points */
static void del_Point(PyObject * obj)
{
    free(PyCapsule_GetPointer(obj, "Point"));
}
  
/* Utility functions */
static Point * PyPoint_AsPoint(PyObject * obj)
{
    return (Point *) PyCapsule_GetPointer(obj, "Point");
}
static PyObject * PyPoint_FromPoint(Point * p, int must_free)
{
    return PyCapsule_New(p, "Point", must_free ? del_Point : NULL);
}
  
/* Create a new Point object */
static PyObject * py_Point(PyObject * self, PyObject * args)
{
    Point * p;
    double x, y;
    if (! PyArg_ParseTuple(args, "dd", &x, &y))
    {
        return NULL;
    }
    p = (Point *) malloc(sizeof(Point));
    p->x = x;
    p->y = y;
    return PyPoint_FromPoint(p, 1);
}
  
static PyObject * py_distance(PyObject * self, PyObject * args)
{
    Point * p1, *p2;
    PyObject * py_p1, *py_p2;
    double result;
    if (! PyArg_ParseTuple(args, "OO", &py_p1, &py_p2))
    {
        return NULL;
    }
    if (!(p1 = PyPoint_AsPoint(py_p1)))
    {
        return NULL;
    }
    if (!(p2 = PyPoint_AsPoint(py_p2)))
    {
        return NULL;
    }
    result = distance(p1, p2);
    return Py_BuildValue("d", result);
}

代码 #3:在Python中使用上述函数

import sample
  
pt1 = sample.Point(2, 3)
pt2 = sample.Point(4, 5)
  
print ("pt1 : ", pt1)
print ("\npt2 : ", pt2)
  
print ("Distance : ", sample.distance(p1, p2))

输出 :

pt1 : 

pt2 : 

Distance : 2.8284271247461903

  • 胶囊类似于类型化的 C 指针。
  • 它们包含一个通用指针和一个标识名称,可以使用PyCapsule_New()函数轻松创建。
  • PyCapsule_GetPointer()函数用于提取胶囊内包含的指针。
  • 垃圾收集和内存管理是涉及胶囊的棘手部分。
  • PyPoint_FromPoint()函数接受一个 must_free 参数,该参数指示当胶囊被破坏时是否要收集底层 Point * 结构。