目次

PythonのクラスオブジェトCの関数に渡す

作成日: 2023-08-04 (金)

第3回 Python/C APIに触れてみる (2)

ソースコード

setup.py

from setuptools import setup, Extension

setup(
    name="pointlib",
    ext_modules=[
        Extension("pointlib", ["pointlibmodule.c"])
    ]
)

point.py

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def to_s(self):
        return "({}, {})".format(self.x, self.y)

pointlibmodule.c

#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <math.h>

static PyObject *pointlib_distance(PyObject *self, PyObject *args) {
    PyObject *point_obj = NULL;
    if (!PyArg_ParseTuple(args, "O", &point_obj)) {
        return NULL;
    }

    PyObject *x_obj = PyObject_GetAttrString(point_obj, "x");
    if (x_obj == NULL) {
        return NULL;
    }

    PyObject *y_obj = PyObject_GetAttrString(point_obj, "y");
    if (y_obj == NULL) {
        Py_XDECREF(x_obj);
        return NULL;
    }

    long x = PyLong_AsLong(x_obj);
    long y = PyLong_AsLong(y_obj);
    Py_XDECREF(y_obj);
    Py_XDECREF(x_obj);

    return PyFloat_FromDouble(sqrt(x * x + y * y));
}

// clang-format off
static PyMethodDef pointlib_methods[] = {
    {"distance", pointlib_distance, METH_VARARGS,
     "Distance from origin to the point."},
    {NULL, NULL, 0, NULL}
};

static PyModuleDef pointlib_module = {
    PyModuleDef_HEAD_INIT,
    "pointlib",
    "Example for passing a Python object to C function.",
    -1,
    pointlib_methods
};
// clang-format on

PyMODINIT_FUNC PyInit_pointlib(void) {
    return PyModule_Create(&pointlib_module);
}