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 Point
s:
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.
I was initially a little confused about this question since it seemed to have no Cython content (sorry the editing mess resulting from that confusion).
The Python cookbook uses Cython in a very odd way which I wouldn't recommend following. For some reason it wants to use PyCapsules which I have never seen used before in Cython.
You can then compile it and use it from Python as
In fairness to the Python Cookbook it then gives a second example that does something very similar to what I've done (but using a slightly older property syntax from when Cython didn't support the Python-like approach). So if you'd have read a bit further you wouldn't have needed this question. But avoid mixing Cython and pycapsules - it isn't a sensible solution and I don't know why they recommended it.