2007-07-18

C++でPython拡張

今日も(睡眠時間を削って)Python拡張の勉強をした。
今日は苦手なC言語ではなく、かすかにましなC++でPython拡張を書くことに挑戦。
試しに、std::vectorをPythonから使うものを書いてみたが、vectorの作成、push_back(), size()を使えるとこまできた。
もう少し実装が進んだら、Pythonのlistとstd::vectorを対決させてみようと思っている。
Python拡張歴3日なので、全くの未熟者で恥ずかしい部分も多々あるとは思うのですが、今日の作業で作ったC++対応のPython拡張のためのテンプレートをコピペしておこう。
ちなみに「boost使うと、、」というツッコミはなしでお願いします。


#include <Python.h>
#include <structmember.h>
/*
## Copyright 2007 Hiroshi Ayukawa (email: ayukawa.hiroshi [atmark] gmail.com)
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
*/

/*
説明
このテンプレートは、Pythonモジュールで型を一つ定義するテンプレートです。
最初にこのファイルを、あなたのプロジェクトに合わせて別名で保存します。
その後、このファイル中の
mytype
という文字列を一括置換で、あなたが定義しようとしている型名に変換します。

基本的にC言語で書いてください。
C++も使えます。その場合はファイルの拡張子を.cppにしたほうがいいかもしれません。(未確認)
C++の場合、公開メソッドは必ず extern "C" 宣言してある必要があります。(そのため、このテンプレートは随所にその宣言があります。)
メソッドを追加する場合はお忘れなきように。

*/

typedef struct {
PyObject_HEAD;
// TODO: ここに型のメンバーを宣言
} mytype;

#ifdef __cplusplus
extern "C"
#endif
static void
mytype_dealloc(mytype* self)
{
// TODO: この型の掃除処理を書く。
self->ob_type->tp_free((PyObject*)self);
}

#ifdef __cplusplus
extern "C"
#endif
static PyObject *
mytype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
mytype *self;
self = (mytype *)type->tp_alloc(type, 0);
// TODO: ここで型のヌル初期化処理を書く
return (PyObject *)self;
}

#ifdef __cplusplus
extern "C"
#endif
static int
mytype_init(mytype *self, PyObject *args, PyObject *kwds)
{
const char* mecabOpt = NULL;

// TODO: 引数処理。ここは適宜書き換えてください。
if(PyArg_ParseTuple(args, "")){
}else{
if(PyArg_ParseTuple(args, "s", &mecabOpt)){
PyErr_Clear();
}else{
PyErr_SetString(PyExc_TypeError, "bad argument(1)");
return -1;
}
}

// TODO: 型の初期化処理を書く。

return 0;
}

static PyMemberDef mytype_members[] = {
// TODO: 公開メンバの設定。
// like this... {"getMecabOpt", T_STRING, offsetof(mytype, mecabOpt), 0, "mecab option"},
{NULL} /* Sentinel */
};

/* method definition example
// TODO: メンバ関数の定義
#ifdef __cplusplus
extern "C"
#endif
static PyObject *
mytype_parse(mytype* self, PyObject* args)
{
//......
}

// method list
// TODO: メンバ関数の宣言
static PyMethodDef mytype_methods[] = {
// like this... {"parse", (PyCFunction)mytype_parse, METH_VARARGS,"Return the parsed result."},
{NULL} // Sentinel
};
*/

//Type declaration
// 型の宣言、基本的にはこのままでたいていはOKと思われる。
static PyTypeObject mytypeType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"mytype.mytype", /*tp_name*/
sizeof(mytype), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)mytype_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"mytype objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
mytype_methods, /* tp_methods */
mytype_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)mytype_init, /* tp_init */
0, /* tp_alloc */
mytype_new, /* tp_new */
};

static PyMethodDef module_methods[] = {
{NULL} /* Sentinel */
};

#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
#ifdef __cplusplus
extern "C" {
#endif
PyMODINIT_FUNC
init_mytype(void)
{
PyObject* m;

mytypeType.tp_new = PyType_GenericNew;
if (PyType_Ready(&mytypeType) < 0)
return;

m = Py_InitModule3("_mytype", mytype_methods,
"Example module that creates an extension type.");

/* in case you would make static global variable
// TODO: ここで静的Globalなどを必要に応じて作る。
SURFACE = PyString_FromString("surface"); // SURFACE shold be declared on the top of this source code like "PyObejct* SURFACE;"
if(SURFACE == NULL) return;
if(PyModule_AddObject(m, "SURFACE", SURFACE)) return;
*/

Py_INCREF(&mytypeType);
PyModule_AddObject(m, "mytype", (PyObject *)&mytypeType);
}

#ifdef __cplusplus
}
#endif