ユーザ用ツール

サイト用ツール


youtube:python-mixing-003x2

CでPythonのクラスを作る

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

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

ソースコード

setup.py

from setuptools import setup, Extension

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

pointlibmodule.c

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

// clang-format off
typedef struct {
    PyObject_HEAD
    double x;
    double y;
} PointObject;
// clang-format on

static int Point_init(PointObject *self, PyObject *args) {
    double x, y;
    if (!PyArg_ParseTuple(args, "dd", &x, &y)) {
        return -1;
    }
    self->x = x;
    self->y = y;
    return 0;
}

static PyObject *Point_to_s(PointObject *self, PyObject *Py_UNUSED(ignored)) {
    char buf[1024];
    snprintf(buf, 1024, "(%lf,%lf)", self->x, self->y);
    return PyUnicode_FromFormat("%s", buf);
}

static PyMemberDef Point_members[] = {
    {"x", T_DOUBLE, offsetof(PointObject, x), 0, "x coord"},
    {"y", T_DOUBLE, offsetof(PointObject, y), 0, "y coord"},
    {NULL}};

static PyMethodDef Point_methods[] = {
    {"to_s", (PyCFunction)Point_to_s, METH_NOARGS, "Return formated string."},
    {NULL, NULL, 0, NULL}};

static PyTypeObject PointType = {
    PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pointlib.Point",
    .tp_doc = PyDoc_STR("Point object"),
    .tp_basicsize = sizeof(PointObject),
    .tp_itemsize = 0,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_new = PyType_GenericNew,
    .tp_init = (initproc)Point_init,
    .tp_members = Point_members,
    .tp_methods = Point_methods,
};

static PyObject *pointlib_distance(PyObject *self, PyObject *args) {
    PyObject *pt1, *pt2;

    if (!PyArg_ParseTuple(args, "OO", &pt1, &pt2)) {
        return NULL;
    }

    PyObject *x1_obj = PyObject_GetAttrString(pt1, "x");
    PyObject *y1_obj = PyObject_GetAttrString(pt1, "y");
    PyObject *x2_obj = PyObject_GetAttrString(pt2, "x");
    PyObject *y2_obj = PyObject_GetAttrString(pt2, "y");

    if (x1_obj == NULL || y1_obj == NULL || x2_obj == NULL || y2_obj == NULL) {
        Py_XDECREF(x1_obj);
        Py_XDECREF(y1_obj);
        Py_XDECREF(x2_obj);
        Py_XDECREF(y2_obj);
        return NULL;
    }

    double x1 = PyFloat_AsDouble(x1_obj);
    double y1 = PyFloat_AsDouble(y1_obj);
    double x2 = PyFloat_AsDouble(x2_obj);
    double y2 = PyFloat_AsDouble(y2_obj);
    double dx = x2 - x1;
    double dy = y2 - y1;
    double dist = sqrt(dx * dx + dy * dy);

    Py_DECREF(x1_obj);
    Py_DECREF(y1_obj);
    Py_DECREF(x2_obj);
    Py_DECREF(y2_obj);

    return PyFloat_FromDouble(dist);
}

static PyMethodDef pointlib_methods[] = {
    {"distance", pointlib_distance, METH_VARARGS,
     PyDoc_STR("Distance between two points.")},
    {NULL, NULL, 0, NULL}};

static PyModuleDef pointlib_module = {
    PyModuleDef_HEAD_INIT,
    .m_name = "pointlib",
    .m_doc = PyDoc_STR("Example module creating custom type."),
    .m_size = -1,
    .m_methods = pointlib_methods,
};

PyMODINIT_FUNC PyInit_pointlib(void) {
    if (PyType_Ready(&PointType) < 0) {
        return NULL;
    }

    PyObject *module = PyModule_Create(&pointlib_module);
    if (module == NULL) {
        return NULL;
    }

    Py_INCREF(&PointType);
    if (PyModule_AddObject(module, "Point", (PyObject *)&PointType) < 0) {
        Py_DECREF(&PointType);
        Py_DECREF(module);
        return NULL;
    }

    return module;
}

youtube/python-mixing-003x2.txt · 最終更新: 2024/02/28 18:26 by freemikan

特に明示されていない限り、本Wikiの内容は次のライセンスに従います: CC0 1.0 Universal
CC0 1.0 Universal Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki