"spam" (Monty Python ファンの好物ですね) という名の拡張モジュールを 作成することにして、C ライブラリ関数 system() に対する Python インタフェースを作成したいとします。 1.1この関数は null で終端されたキャラクタ文字列を引数にとり、 整数を返します。この関数を以下のようにして Python から呼び出せるように したいとします:
>>> import spam >>> status = spam.system("ls -l")
まずは spammodule.c を作成するところから始めます。 (伝統として、"spam" という名前のモジュールを作成する場合、 モジュールの実装が入った C ファイルを spammodule.c と 呼ぶことになっています; "spammify" のように長すぎる モジュール名の場合には、単にspammify.c にもできます。)
このファイルの最初の行は以下のようにします:
#include <Python.h>
これで、Python API を取り込みます (必要なら、モジュールの用途に 関する説明や、著作権表示を追加します)。 Python は、システムによっては標準ヘッダの定義に影響するような プリプロセッサ定義を行っているので、 Python.h は いずれの標準ヘッダよりも前にインクルードせねばなりません。
Python.h で定義されているユーザから可視のシンボルは、
全て接頭辞"Py" または "PY" が付いています。ただし、
標準ヘッダファイル内の定義は除きます。
簡単のためと、Python 内で広範に使うことになるという理由から、
"Python.h"
はいくつかの標準ヘッダファイル:
<stdio.h>
、 <string.h>
、 <errno.h>
、および
<stdlib.h>
をインクルードしています。
後者のヘッダファイルがシステム上になければ、"Python.h"
が
関数 malloc()、free() および
realloc() を直接定義します。
次にファイルに追加する内容は、Python 式 "spam.system(string)"を評価する際に呼び出されることになる C 関数です (この関数を最終的にどのように呼び出すかは、後ですぐわかります):
static PyObject * spam_system(PyObject *self, PyObject *args) { const char *command; int sts; if (!PyArg_ParseTuple(args, "s", &command)) return NULL; sts = system(command); return Py_BuildValue("i", sts); }
ここでは、Python の引数リスト (例えば、単一の式 "ls -l"
)
から C 関数に渡す引数にそのまま変換しています。
C 関数は常に二つの引数を持ち、便宜的に self および args
と呼ばれます。
self 引数は C 関数が Python の関数ではなく組み込みメソッド を実装している場合にのみ使われます。この例ではメソッドではなく 関数を定義しているので、 self は常に NULL ポインタになります。 (これは、インタプリタが二つの異なる形式の C 関数を理解しなくてもよく するためです。)
args 引数は、引数の入った Python タプルオブジェクトへの ポインタになります。タプル内の各要素は、呼び出しの際の引数リストに おける各引数に対応します。引数は Python オブジェクトです -- C 関数で引数を使って何かを行うには、オブジェクトから C の値に 変換せねばなりません。Python API の関数 PyArg_ParseTuple() は引数の型をチェックし、C の値に変換します。 PyArg_ParseTuple() はテンプレート文字列を使って、 引数オブジェクトの型と、変換された値を入れる C 変数の型を判別します。 これについては後で詳しく説明します。
PyArg_ParseTuple() は、全ての引数が正しい型を持っていて、 アドレス渡しされた各変数に各引数要素を保存したときに真 (非ゼロ) を 返します。この関数は不正な引数リストを渡すと偽 (ゼロ) を返します。 後者の場合、関数は適切な例外を送出するので、呼び出し側は (例にもあるように) すぐにNULL を返すようにしてください。