C++で簡単なPythonのライブラリを作ります。
整数同士を掛け算する関数です。
さっそくコードを示します。
# setup.py from distutils.core import setup, Extension setup(name = 'mymath', version = '1.0.0', \ ext_modules = [Extension('mymath', ['mymath.cpp'])])
// mymath.cpp #include <Python.h> static PyObject *mul(PyObject *self, PyObject *args) { int a, b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) return NULL; const int c = a * b; return Py_BuildValue("i", c); } static PyMethodDef mymathMethods[] = { { "mul", mul, METH_VARARGS }, { NULL } }; static struct PyModuleDef mymath = { PyModuleDef_HEAD_INIT, "mymath", "Python3 C API Module", -1, mymathMethods }; PyMODINIT_FUNC PyInit_mymath() { return PyModule_Create(&mymath); }
ポイントは型変換です。
Pythonからやってくる値はPyObjectで、返す値もPyObjectなので、PyObjectをintに変換して、計算した結果のintをPyObjectに変換します。
まず、PyObjectをintに変換する部分です。
int a, b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) return NULL;
タプルなので、PyObjectを一つずつ取り出して、それをintにしてもよいです。
PyObject *obj1 = PyTuple_GetItem(args, 0); PyObject *obj2 = PyTuple_GetItem(args, 1); if(!PyLong_Check(obj1)) return Py_None; if(!PyLong_Check(obj2)) return Py_None; const int a = PyLong_AsLong(obj1); const int b = PyLong_AsLong(obj2);
タプルオブジェクト (tuple object) - Python 3.9.1 ドキュメント
整数型オブジェクト (integer object) - Python 3.9.1 ドキュメント
上のように、PyArg_ParseTupleを使うと一度にintを2つ取り出せます。
PyArg_ParseTupleの第2引数がどの型に変換するかを指定しています。"ii"だと2つともintに変換します。
引数の解釈と値の構築 - Python 3.9.1 ドキュメント
実行してみましょう。
$ python Python 3.7.4 (default, Aug 13 2019, 20:35:49) [GCC 7.3.0] :: Anaconda, Inc. on linux Type "help", "copyright", "credits" or "license" for more information. >>> import mymath >>> mymath.mul(2, 3) 6
次の例だと、
>>> mymath.mul(100000, 100000) 1410065408
32ビット符号付き整数なので、ちゃんとオーバーフローしていますね。
>>> (100000*100000+2**31)%2**32-2**31 1410065408
あってます。