Skip to content
Related Articles

Related Articles

Improve Article

C API from Extension Module in Python | Set 1

  • Last Updated : 27 Mar, 2019

Suppose given a C extension module that internally defines a variety of useful functions that can be exported as a public C API for use elsewhere. Now if we want to use these functions inside other extension modules. Then, it is important to know how to link them together but doing it with the C compiler/linker seems excessively complicated.

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;

 
Code #3 : Import the API table from “work”






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 table of function pointers is the most important feature as it will be initialized in the exporting module and found by importing modules. The code below shows how to change the original extension module to populate the table and export it.

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\n");
    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;
}

 Attention geek! Strengthen your foundations with the Python Programming Foundation Course and learn the basics.  

To begin with, your interview preparations Enhance your Data Structures concepts with the Python DS Course. And to begin with your Machine Learning Journey, join the Machine Learning – Basic Level Course




My Personal Notes arrow_drop_up
Recommended Articles
Page :