====== CでPythonのクラスを作る ====== 作成日: 2023-08-04 (金) [[https://youtu.be/kYp_yQfunhU|第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 #include // 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; }