HOME | ドキュメント |  ブログ  |  BBS  |  瓦版  | 将棋プロジェクト |  物置小屋   

Python パイソン Python から C++ クラスを呼び出す
 道標
象歩
象歩ブログ
ドキュメント
自転車整備ノート
C/C++
Linux 備忘録
パソコン整備ノート
不健康日記
不健康日記 (2)
Python パイソン
PythonからCプログラ~
Python から C++ クラ~
PythonからC++クラス~
SpamBayes 日本語化
UDP通信のサンプルコ~
XMLRPC サンプルコー~
セキュリティ
Vine ヴァイン
Zope2 (ゾープ 2.x 系)
象歩BBS
Web瓦版
将棋プロジェクト
物置小屋
 リンク
python.org
document
SourceForge.net: Python
wiki.python.org
wiki.python.org/moin/TkInter
PIL/Tkinter
Mark Hammond's Free Stuff
Tcl/Tk Manual Pages
Python development with Eclipse and Ant
Dive Into Python
Python HOWTOs
Richard Gruet's Home page
日本Pythonユーザ会
Python チュートリアル
Python 標準ドキュメント
Python 2.4 Quick Reference
正規表現 HOWTO
PythonSpeed 日本語訳
Python おもちゃばこ (仮称)
ASPN Python Cookbook
PEP 8 -- Style Guide for Python Code
Pythonイントロスペクション入門
Pythonでの永続性管理
numarray日本語訳
複雑なモデルをシンプルにするSimPy
python での行列・ベクトル数値計算
Gembook.jp
NoboNoboRTD
岩田さん
松本さん
増田さん
py2exeモジュールについて
Django オンラインドキュメント和訳(へのリンク)
Tcl/Tk と Tkinter
SQLObject 日本語訳
The Python IAQ: Infrequently Answered Questions 日本語訳
Python 調査報告
Django オンラインドキュメント和訳
紫藤のページ
M.Hiroi's Home Page
Tcl/Tk 屋根裏が入口

PythonからCプログラムを呼び出す  [更新日:2007年12月04日]

Python でプログラミングしていると、 新しいデータ構造を作り上げる場合などに、 C/C++ の力を借りたくなることがあります。 Python から C/C++ コードを呼び出す方法を書きます。 まずは、Cから...

1.ソースコード

次の関数を題材にします。
// hello.c
int add(int x, int y)
{
	return x + y;
}

void out(const char* adrs, const char* name)
{
	printf("こんにちは、私は %s の %s です。\n", adrs, name);
}

2.wrapper コード

まずモジュール(ライブラリ)名を決めます。 ここでは "hello" とします。 そしてラッパモジュールを書きます。

// helloWrapper.c
#include "Python.h"
extern int add(int, int);
extern void out(const char*, const char*);

PyObject* hello_add(PyObject* self, PyObject* args)
{
	int x, y, g;

	if (!PyArg_ParseTuple(args, "ii", &x, &y))
		return NULL;
	g = add(x, y);
	return Py_BuildValue("i", g);
}

PyObject* hello_out(PyObject* self, PyObject* args, PyObject* kw)
{
	const char* adrs = NULL;
	const char* name = NULL;
	static char* argnames[] = {"adrs", "name", NULL};

	if (!PyArg_ParseTupleAndKeywords(args, kw, "|ss",
			argnames, &adrs, &name))
		return NULL;
	out(adrs, name);
	return Py_BuildValue("");
}

static PyMethodDef hellomethods[] = {
	{"add", hello_add, METH_VARARGS},
	{"out", hello_out, METH_VARARGS | METH_KEYWORDS},
	{NULL},
};

void inithello()
{
	Py_InitModule("hello", hellomethods);
}

インクルード文 - 必須

最初に "Python.h" をインクルードします。

#include "Python.h"

関数の定義

関数とラッパは一対一に対応させるのが解りやすいでしょう。 例えば wrapper 関数名は "モジュール名_関数名" などと決めます。

関数定義はつぎの二通りおこなっています。

PyObject* hello_add(PyObject* self, PyObject* args)
PyObject* hello_out(PyObject* self, PyObject* args, PyObject* kwargs)
後の定義は、キーワード引数を利用する場合です。

引数の解読

Python からの呼び出しが"位置による引数"の場合は次の関数を使います。

PyArg_ParseTuple(PyObject* args, const char* fmt, ...)

また呼び出しが"キーワード引数"の場合は次の関数を使います。

PyArg_ParseTupleAndKeywords(PyObject* args, const char* fmt,
	const char* argnames, ...)

"const char* fmt" は引数の変換書式です。 printf (C の関数) の書式にちょっと似ています。

書式Python型C型 説明
"c" 文字列 char 一文字
"s" 文字列 char* 文字列
"i" 整数 int 整数
"l" 整数 long 整数
"f" 実数 float 浮動小数点数
"d" 実数 double浮動小数点数
"|"     オプション開始

戻り値

関数の戻り値は次の様に設定します。
	return Py_BuildValue(const char* fmt, ...);
戻り値がない場合はヌル文字を返します。
	return Py_BuildValue("");
NULL を返した場合は実行エラーになります。

初期化関数

最初に関数の対応テーブルを作ります。

static PyMethodDef hellomethods[] = {
	{"add", hello_add, METH_VARARGS},
	{"out", hello_out, METH_VARARGS | METH_KEYWORDS},
        {NULL},
};
ここで Python 呼び出し名とラッパ関数名の対応を付けます。 "add", "out" は python メソッド名です。 "hello_add", "hello_out" はラッパ関数名です。 "hello_out"はキーワード付きなので "METH_KEYWORDS" を論理和します。

コンパイルすると、ここで

helloWrapper.c:37: --- hello_out の行
warning: initialization from incompatible pointer type
と警告が出ます。 プロトタイプ宣言不一致に対する警告のようなので特に問題は無いと思います。

初期化関数はつぎのように書きます。

void inithello()
{
	Py_InitModule("hello", hellomethods);
}
モジュール名が "hello" の場合、初期化関数名は "inithello" とします。 Python でモジュールが import された時に呼び出されます。

3.ビルド

コンパイルし、共有ライブラリを作成します。
$ gcc -fpic -o hello.o -c hello.c
$ gcc -fpic -I/usr/include/python -o helloWrapper.o -c helloWrapper.c
$ gcc -shared hello.o helloWrapper.o -o hellomodule.so
ここで作成するライブラリ名はモジュール名と一致しなければなりません。 モジュール名が "hello" なら、 ライブラリ名は "hellomodule.so" となります。 インクルードヘッダのパスは環境によって違います。

4.実行

以下のように実行し確認します。

$ /usr/bin/python
>>> import hello
>>> hello.add(2, 3)
5
>>> hello.out("大原", "麗子")
今日は、私は 大原 の 麗子 です。 
>>>^D
$
このようにできたら成功と言えます。

5.参考資料

「Python入門」 Mark Lutz

- ISBN4-900900-55-9 O'REILLY

「Pythonテクニカルリファレンス」 David M.Beazley

- ISBN4-89471-221-0 ピアソン・エデュケーション