1.1 簡単な例

"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 を返すようにしてください。



脚注

... インタフェースを作成したいとします。1.1
この関数へのインタフェースはすでに標準モジュール os にあります -- この関数を選んだのは、単純で直接的な例を示したいからです。
ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。