Disclaimer: I took the following example from the Python Cookbook (O'Reilly).
Let's say I have the following simple struct:
typedef struct {
double x,y;
} Point;
with a function that calculates the Euclidean distance between two Points:
extern double distance(Point* p1, Point* p2);
All this is part of a shared library called points:
points.h- the header filepoints.c- the source filelibpoints.so- the library file (the Cython extension links against it)
I have created my wrapping Python script (called pypoints.py):
#include "Python.h"
#include "points.h"
// Destructor for a Point instance
static void del_Point(PyObject* obj) {
// ...
}
// Constructor for a Point instance
static void py_Point(PyObject* obj) {
// ...
}
// Wrapper for the distance function
static PyObject* py_distance(PyObject* self, PyObject* arg) {
// ...
}
// Method table
static PyMethodDef PointsMethods[] = {
{"Point", py_Point, METH_VARARGS, "Constructor for a Point"},
{"distance", py_distance, METH_VARARGS, "Calculate Euclidean distance between two Points"}
}
// Module description
static struct PyModuleDef pointsmodule = {
PyModuleDef_HEAD_INIT,
"points", // Name of the module; use "import points" to use
"A module for working with points", // Doc string for the module
-1,
PointsMethods // Methods provided by the module
}
Note that this is just an example. For the struct and function above I can easily use ctypes or cffi but I want to learn how to write Cython extensions. The setup.py is not required here so no need to post it.
Now as you can see the constructor above allows us to do
import points
p1 = points.Point(1, 2) # Calls py_Point(...)
p2 = points.Point(-3, 7) # Calls py_Point(...)
dist = points.distance(p1, p2)
It works great. However what if I want to actually access the internals of the Point structure? For example how would I do
print("p1(x: " + str(p1.x) + ", y: " + str(p1.y))
As you know a struct internals can be directly accessed (if we use C++ terminology we can say that all struct members are public) so in a C code we can easily do
Point p1 = {.x = 1., .y = 2.};
printf("p1(x: %f, y: %f)", p1.x, p1.y)
In Python class members (self.x, self.y) can also be accessed without any getters and setters.
I can write functions which act as an intermediate step:
double x(Point* p);
double y(Point* p);
however I am unsure how to wrap these and how to describe their call inside the table of methods.
How can I do that? I want to have a simple p1.x for getting the x of my Point structure in Python.
double x(Point* p);is a function declaration of a function namedxwhich takes a pointer to aPointas an argument and returns adouble— so you should be able to wrap (as well as write) it. Likewise foryfunction.p1.xandp1.ynotation Python, given a class likePoint, you could create properties (with associated getters and possibly also setters) for an attributes namedxand another one fory. Not sure if it's possible to implement properties to Cython.