PythonのC拡張を書く。

Cのアルゴリズム本で漸化式のサンプルがあったのをPythonのC拡張に試しに落とし込んでみた。

<some_dir>/
| -- build.sh
| -- ext.c
`-- tests.py 

ext.c

longのオーバーフロー処理はしてないです。悪しからず。

#include <Python.h>

long combi(int, int);

static PyObject *
recurrence_formula(PyObject *self, PyObject *args){
  int arg;
  int n, r;
  PyListObject *list;

  if(!PyArg_ParseTuple(args, "i", &arg)){
    return NULL;
  }

  list = (PyListObject *) PyList_New(arg);

  for(n=0; n<arg; n++){
    for(r=0; r<=n; r++){
      PyList_SET_ITEM(list, r, Py_BuildValue("l", combi(n, r)));
    }
  }

  return Py_BuildValue("O", list);
}

long combi(int n, int r){
  int i;
  long p=1;

  for(i=1; i<=r; i++){
    p = p * (n - i + 1) / i;
  }

  return p;
}

// ext.__doc__                                                                                                                                                                                                                             
static char ext_doc[] = "C extention module documentation.";

// ext.recurrence_formula.__doc__                                                                                                                                                                                                          
static char recurrence_formula_docs[] = "list recurrence_formula(int): return result number that recurrence formula .";

// ext.<function name>.__doc__                                                                                                                                                                                                             
static PyMethodDef methods[] = {
  {"recurrence_formula", recurrence_formula, METH_VARARGS, recurrence_formula_docs},
  {NULL, NULL}
};

void initext(void)
{
  Py_InitModule3("ext", methods, ext_doc);
}

tests.py

簡単なテスト書いとくと楽だった。

import unittest
try:
    import ext
except ImportError, e:
    raise e

class TestSequenceFunctions(unittest.TestCase):

    def setUp(self):
        pass

    def test_recurrence_formula(self):
        array = ext.recurrence_formula(1)
        self.assertEqual(array, [1])

        array = ext.recurrence_formula(10)
        self.assertEqual(array, [1, 9, 36, 84, 126, 126, 84, 36, 9, 1])

	try:
            array = ext.recurrence_formula("argument is string.")
	except TypeError:
            self.assert_("argument is stirng.")

if __name__ == '__main__':
    unittest.main()

build.sh

コンパイルとテストを自動化しとくと楽だった。

#!/bin/bash

# old file delete. 
#rm -f ext.o
#rm -f ext.so

# compile.
gcc -fPIC -c ext.c -I /usr/include/python2.6/
gcc -shared -O3 -o ext.so ext.o

# test sweet.
echo "Unit Test"
python tests.py

まとめ。

  • Cはhelloworld程度しか書いたことなかたけど、動くとこまではできた。
    • これがベストプラクティスかは別。
  • 意外と簡単に作れた。ドキュメントそろってるから楽。

追記

ファイル構成変えてbitbucketにコミットした。