Python | Непрозрачные указатели в модулях расширения C

Опубликовано: 12 Апреля, 2022

Давайте обсудим модуль расширения, который должен обрабатывать указатель на структуру данных C, не раскрывая какие-либо внутренние детали структуры Python. Непрозрачные структуры данных можно легко обработать, заключив их в объекты капсулы, как показано в фрагменте кода ниже.

Code #1 :

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

Обратитесь к предыдущей статье, чтобы найти функцию distance () - Использование кодов C в Python.

Code #2 : Code given is an extension code that wraps the Point structure and distance() function using capsules.

/* 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 (" pt2 : ", pt2)
  
print ("Distance : ", sample.distance(p1, p2))

Выход :

pt1: <объект-капсула "Point" по адресу 0x1004ea330>

pt2: <объект-капсула "Point" по адресу 0x1005d1db0>

Расстояние: 2.8284271247461903

 

  • Capsules are similar to a typed C pointer.
  • They hold a generic pointer along with an identifying name and can be easily created using the PyCapsule_New() function.
  • PyCapsule_GetPointer() function is used to extract the pointer contained inside a capsule.
  • Garbage collection and memory management is a tricky part that concerns about the capsules.
  • PyPoint_FromPoint() function accepts a must_free argument that indicates whether the underlying Point * structure is to be collected when the capsule is destroyed.

Внимание компьютерщик! Укрепите свои основы с помощью базового курса программирования Python и изучите основы.

Для начала подготовьтесь к собеседованию. Расширьте свои концепции структур данных с помощью курса Python DS. А чтобы начать свое путешествие по машинному обучению, присоединяйтесь к курсу Машинное обучение - базовый уровень.