C API из модуля расширения в Python | Комплект 1

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

Предположим, что имеется модуль расширения C, который внутренне определяет множество полезных функций, которые можно экспортировать как общедоступный C API для использования в другом месте. Теперь, если мы хотим использовать эти функции внутри других модулей расширения. Затем важно знать, как связать их вместе, но сделать это с помощью компилятора / компоновщика C кажется чрезмерно сложным.

Code #1 : [C code] Point objects including some utility functions

# Destructor function for points
static void del_Point(PyObject *obj)
{
    free(PyCapsule_GetPointer(obj, "Point"));
}
  
static PyObject *PyPoint_FromPoint(Point *p, int must_free)
{
    return PyCapsule_New(p, "Point", must_free ? del_Point : NULL);
}
  
# Utility functions 
static Point *PyPoint_AsPoint(PyObject *obj)
{
    return (Point *) PyCapsule_GetPointer(obj, "Point");
}

Now, the issue to deal with is how to handle the exportation of the PyPoint_AsPoint() and PyPoint_FromPoint() functions as an API that can be used by and can link to other extension modules. (For example – any other extensions also want to use the wrapped Point objects).

 
Code #2 : Introducing a new header file called Pythonsample.h for the work extension.

//pythonsample.h
#include "Python.h"
#include "work.h"
#ifdef __cplusplus
  
extern "C" {
#endif
  
// Public API Table
    typedef struct
    {
        Point *(*aspoint)(PyObject *);
        PyObject *(*frompoint)(Point *, int);
    } _PointAPIMethods;
  
#ifndef PYTHONSAMPLE_MODULE
  
    /* Method table in external module */
    static _PointAPIMethods *_point_api = 0;


Код № 3: Импортировать таблицу API из «работы»

static int import_sample(void)
{
    _point_api = (_PointAPIMethods *) PyCapsule_Import("work._point_api", 0);
    return (_point_api != NULL) ? 1 : 0;
}
/* Macros to implement the programming interface */
#define PyPoint_AsPoint(obj) (_point_api->aspoint)(obj)
#define PyPoint_FromPoint(obj) (_point_api->frompoint)(obj)
#endif
#ifdef __cplusplus
}
#endif


Таблица указателей функций _PointAPIMethods является наиболее важной функцией, поскольку она будет инициализирована в модуле экспорта и найдена при импорте модулей. В приведенном ниже коде показано, как изменить исходный модуль расширения для заполнения таблицы и ее экспорта.

Code #4 : Destructor and Utility Function

// pythonsample.c
# include "Python.h"
# define PYTHONSAMPLE_MODULE
# include "pythonsample.h"
  
// Destructor function for points 
static void del_Point(PyObject * obj)
{
    printf("Deleting point ");
    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 free)
{
    return PyCapsule_New(p, "Point", free ? del_Point : NULL);
}
  
static _PointAPIMethods _point_api =
{
    PyPoint_AsPoint,
    PyPoint_FromPoint
};

 
Code #5 : Module function

// Module initialization function 
  
PyMODINIT_FUNC
PyInit_sample(void)
{
    PyObject *m;
    PyObject *py_point_api;
    m = PyModule_Create(&samplemodule);
    if (m == NULL)
        return NULL;
          
    // Add the Point C API functions
    py_point_api = PyCapsule_New((void *) &_point_api, "work._point_api", NULL);
    if (py_point_api)
    {
        PyModule_AddObject(m, "_point_api", py_point_api);
    }
    return m;
}

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

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