これまでは、Python からの C 関数の呼び出しに重点を置いて 述べてきました。ところでこの逆: C からの Python 関数の呼び出し もまた有用です。 とりわけ、いわゆる ``コールバック'' 関数をサポートするような ライブラリを作成する際にはこの機能が便利です。 ある C インタフェースがコールバックを利用している場合、 同等の機能を提供する Python コードでは、しばしば Python プログラマに コールバック機構を提供する必要があります; このとき実装では、 C で書かれたコールバック関数から Python で書かれたコールパック関数 を呼び出すようにする必要があるでしょう。 もちろん、他の用途も考えられます。
幸運なことに、Python インタプリタは簡単に再帰呼び出しでき、 Python 関数を呼び出すための標準インタフェースもあります。 (Python パーザを特定の入力文字を使って呼び出す方法について 詳説するつもりはありません -- この方法に興味があるなら、 Python ソースコードの Python/pythonmain.c にある、 コマンドラインオプション-c の実装を見てください)
Python 関数の呼び出しは簡単です。まず、C のコードに対して コールバックを登録しようとする Python プログラムは、何らかの方法で Python の関数オブジェクトを渡さねばなりません。このために、 コールバック登録関数 (またはその他のインタフェース) を提供 せねばなりません。このコールバック登録関数が呼び出された際に、 引き渡された Python 関数オブジェクトへのポインタをグローバル変数に -- あるいは、どこか適切な場所に -- 保存します (関数オブジェクトをPy_INCREF() するようよく注意して ください!)。例えば、以下のような関数がモジュールの一部になって いることでしょう:
static PyObject *my_callback = NULL; static PyObject * my_set_callback(PyObject *dummy, PyObject *args) { PyObject *result = NULL; PyObject *temp; if (PyArg_ParseTuple(args, "O:set_callback", &temp)) { if (!PyCallable_Check(temp)) { PyErr_SetString(PyExc_TypeError, "parameter must be callable"); return NULL; } Py_XINCREF(temp); /* 新たなコールバックへの参照を追加 */ Py_XDECREF(my_callback); /* 以前のコールバックを捨てる */ my_callback = temp; /* 新たなコールバックを記憶 */ /* "None" を返す際の定型句 */ Py_INCREF(Py_None); result = Py_None; } return result; }
この関数はMETH_VARARGS フラグを使ってインタプリタに 登録せねばなりません; METH_VARARGS フラグについては、 1.4 節、 ``モジュールのメソッドテーブルと初期化関数'' で説明しています。 PyArg_ParseTuple() 関数とその引数については、 1.7 節、 ``拡張モジュール関数でのパラメタ展開'' に記述しています。
Py_XINCREF() およびPy_XDECREF() は、 オブジェクトに対する参照カウントをインクリメント/デクリメントする ためのマクロで、NULL ポインタが渡されても安全に操作できる 形式です (とはいえ、上の流れではtemp がNULL になることは ありません)。 これらのマクロと参照カウントについては、1.10 節、 ``参照カウント'' で説明しています。
その後、コールバック関数を呼び出す時が来たら、C 関数 PyEval_CallObject() を呼び出します。 この関数には二つの引数: Python 関数と Python 関数の引数リストがあり、 いずれも任意の Python オブジェクトを表すポインタ型です。 引数リストは常にタプルオブジェクトでなければならず、その長さは 引数の数になります。Python 関数を引数なしで呼び出すのなら 空のタプルを渡します; 単一の引数で関数を呼び出すのなら、 単要素 (singleton) のタプルを渡します。 Py_BuildValue() の書式化文字列中に、ゼロ個または 一個以上の書式化コードが入った丸括弧がある場合、この関数は タプルを返します。以下に例を示します:
int arg; PyObject *arglist; PyObject *result; ... arg = 123; ... /* ここでコールバックを呼ぶ */ arglist = Py_BuildValue("(i)", arg); result = PyEval_CallObject(my_callback, arglist); Py_DECREF(arglist);
PyEval_CallObject() は Python オブジェクトへのポインタを 返します; これは Python 関数からの戻り値になります。 PyEval_CallObject() は、引数に対して ``参照カウント中立 (reference-count-neutral)'' です。 上の例ではタプルを生成して引数リストとして提供しており、この タプルは呼び出し直後に Py_DECREF() しています。
PyEval_CallObject() は ``新しい'' 戻り値を返します: 戻り値が表すオブジェクトは新たなオブジェクトか、既存のオブジェクトの 参照カウントをインクリメントしたものです。従って、このオブジェクトを グローバル変数に保存したいのでないかぎり、 たとえこの戻り値に興味がなくても (むしろ、そうであればなおさら!) 何がしかの方法で戻り値オブジェクトを Py_DECREF() しなければなりません。
とはいえ、戻り値をPy_DECREF() する前には、値が NULL でないかチェックしておくことが重要です。もし NULLなら、呼び出した Python 関数は例外を送出して終了させられています。 PyEval_CallObject() を呼び出しているコード自体もまた Python から呼び出されているのであれば、今度は C コードが自分を 呼び出している Python コードにエラー標示値を返さねばなりません。 それにより、インタプリタはスタックトレースを出力したり、例外を 処理するための Python コードを呼び出したりできます。 例外の送出が不可能だったり、したくないのなら、 PyErr_Clear() を呼んで例外を消去しておかねばなりません。 例えば以下のようにします:
if (result == NULL) return NULL; /* エラーを返す */ ...use result... Py_DECREF(result);
Python コールバック関数をどんなインタフェースにしたいかによっては、 引数リストをPyEval_CallObject() に与えなければ ならない場合もあります。 あるケースでは、コールバック関数を指定したのと同じインタフェース を介して、引数リストも渡されているかもしれません。 また別のケースでは、新しいタプルを構築して引数リストを渡さねば ならないかもしれません。この場合最も簡単なのは Py_BuildValue() を呼ぶやり方です。 例えば、整数のイベントコードを渡したければ、以下のようなコードを 使うことになるでしょう:
PyObject *arglist; ... arglist = Py_BuildValue("(l)", eventcode); result = PyEval_CallObject(my_callback, arglist); Py_DECREF(arglist); if (result == NULL) return NULL; /* エラーを返す */ /* 場合によってはここで結果を使うかもね */ Py_DECREF(result);
"Py_DECREF(arglist)" が呼び出しの直後、エラーチェックよりも前に 置かれていることに注意してください! また、厳密に言えば、このコードは 完全ではありません: Py_BuildValue() はメモリ不足に おちいるかもしれず、チェックしておくべきです。
ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。