Contents
Python APIはPythonインストール標準のC言語APIを使用し、拡張モジュールを作成します。
PythonAPIを使用したCソースを準備します。
#include <Python.h>
static PyObject *
fact(PyObject *self, PyObject *args)
{
int n;
int i;
int ret=1;
if (!PyArg_ParseTuple(args, "i", &n))
return NULL;
for (i=n; i>0; i--) ret *= i;
return Py_BuildValue("i", ret);
}
static PyObject *
hello(PyObject *self)
{
printf("Hello World!!\n");
Py_RETURN_NONE;
}
static char ext_doc[] = "C extention module example\n";
static PyMethodDef methods[] = {
{"hello", (PyCFunction)hello, METH_NOARGS, "print hello world.\n"},
{"fact", fact, METH_VARARGS, "return factorial.\n"},
{NULL, NULL, 0, NULL}
};
void initext(void)
{
Py_InitModule3("ext", methods, ext_doc);
}
$ gcc -Wall -fPIC -c ext.c -I/usr/include/python2.6
$ gcc -shared -o ext.so ext.o
$ ls
ext.c ext.o ext.so
>>> import ext
>>> ext.hello()
Hello World!!
>>> ext.fact(5)
120
>>> ext.fact(10)
3628800
PythonAPIに最適化されていない生のCソースで作成した共有ライブラリ内の関数を モジュールアクセスで呼び出すことができます。 Python2.5からは標準ライブラリとして使用することができます。
以下のようなCソースを準備するだけです。
#include <stdio.h>
void hello(void)
{
printf("Hello World!!\n");
}
int fact(int n)
{
int i;
int ret=1;
for (i=n; i>0; i--) ret *= i;
return ret;
}
GCCを使っていつもどおりの共有ライブラリを作成します。
gcc -Wall -fPIC -c ext.c -I/usr/include/python2.6
gcc -shared -o ext.so ext.o
ctypes を使ってモジュールにアクセスしてみます。
>>> import ctypes
>>> ext = ctypes.CDLL("./ext.so")
>>> ext.hello()
Hello World!!
>>> ext.fact(5)
120
>>> ext.fact(10)
3628800
プロジェクトページ : SWIG
別途インターフェースファイル(*.i)を用意することで、 Cのスタイルを保ったコードで拡張モジュールを記述できます。 使ってみた感想としては、ラッピング関数を定義したファイルが作成され ファイル構成がやや煩雑になりますが、PythonAPIをいちいち調べたりしなくてもよいので、 より規模の大きなモジュールを作成する際などは、生産性の面で有利かなと感じました。 SWIGがインストールされている必要があります。
Cソース( ext.c )は以下になります。
#include <stdio.h>
void hello(void)
{
printf("Hello World!!\n");
}
int fact(int n)
{
int i;
int ret=1;
for (i=n; i>0; i--) ret *= i;
return ret;
}
インターフェースファイル( ext.i )は以下のような内容になります。
%module ext
%{
extern int fact(int n);
extern void hello(void);
%}
extern int fact(int n);
extern void hello(void);
swig コマンドで後ほど作成する共有ライブラリ( _ext.so )にアクセスする Pythonのラッパースクリプト( ext.py )と ext.cをラッピングするCソース( ext_wrap.c)が作成されます。
$ swig -python ext.i
$ ls
ext.py ext_wrap.c
$ gcc -Wall -fPIC -c ext.c ext_wrap.c -I/usr/include/python2.6
$ gcc -shared -o _ext.so ext.o ext_wrap.o
プロジェクトページ : Pyrex
Python拡張モジュール作成用のPythonライクな構文を持つ言語と、 それをC言語に変換するツールセット(pyrexc)を含む処理系です。 個人的には若干構文が気に入らない感じです。Pyrex構文を覚えないとだめなのが。。。
def hello():
print "Hello World!!"
def fact(int n):
cdef int i
cdef int ret
ret = 1
i = n
while i > 0:
ret *= i
i -= 1
return ret
$ pyrexc ext.pyx
$ gcc -Wall -fPIC -c ext.c -I/usr/include/python2.6
$ gcc -shared -o ext.so ext.o
pyrexc での変換がどこまで対応できるのかが気になります。
プロジェクトページ : Cython
Pyrexの派生であり、Pythonと上位互換があります。 よってPyrexよりもよりPythonらしく記述できます。
def hello():
print "Hello World!!"
def fact(n):
ret = 1
i = n
while i > 0:
ret *= i
i -= 1
return ret
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("ext", ["ext.pyx"])]
setup(
name = 'C extention module example',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
$ python setup.py build_ext --inplace
$ ls
build ext.c ext.so
Pyrexと同じく大規模なモジュールでうまく作成できるかどうかが 気になるところです。