ラッパーの作成
Pythonから呼び出した際の引数の処理及び戻り値の定義を行う関数を定義する.
what_doYouDoの引数
self,
args,
kwはぞれぞれ関数自身,引数,キーワード.いずれも
PyObject型の構造体で参照渡しらしい.
PyArg_ParseTupleAndKeywordsで引数とキーワードを解析している.詳細:
+
引数の解釈と値の構築 — Python 3.13.3 ドキュメント
3つ目の引数(ここでは
"|s")は
Pythonで与えられた引数を
Cのどの型に変換するかという情報を与える.代表的なものとして
"s"は文字列を指すポインタ,
"i"は
int型,
"d"は
double float型など.
"|"以降はキーワード引数,つまり無くても関数が動作する引数.ここでは位置引数(必須の引数)が無く
"jobs"というキーワード引数のみで,これが文字列と想定しているので
"|s"となる.型についての詳細:
+
引数の解釈と値の構築 — Python 3.13.3 ドキュメント
4つ目の引数(
argnames)は「The keywords argument is a NULL-terminated array of keyword parameter names...」(ドキュメントより)とのことで,この例のように,キーワードの一覧の後ろに
NULLを加えたものを与える.
Python側で引数の与え方を誤ると,引数の解析に失敗し,
PyArg_ParseTupleAndKeywordsが偽
(False)を返す.その場合この例では
NULLを返す.
また引数
"jobs"はキーワード引数ということで,
Pythonから値が与えられない場合未定義の状態になってしまうので,
で定義しておく.
引数の解析に成功すると,いよいよ
Cの関数
doYouDoが呼び出される.
最後に戻り値を
Py_BuildValueで
Pythonオブジェクトに変換する.
この関数のように戻り値を持たない場合は空の文字列を入れる.
戻り値がある場合は
Py_BuildValue(format, value1, value2, ...)のような形で,
Cの変数
value1, value2, ...を
formatに従って
Pythonオブジェクトに変換したものを返す.
formatは先の
PyArg_ParseTupleAndKeywordsと同じ(多分).詳細:
+
引数の解釈と値の構築 — Python 3.13.3 ドキュメント
モジュールに入れる手続きのリストアップ
括弧
{}内の引数は
{手続き名, ラッパーのオブジェクト, 引数の与え方, (わからん)}
1つ目の「手続き名」は
Cの関数名と同じである必要は無く,任意に決められるらしい.
Python側から呼び出すときにどういう名前でその手続きを呼び出したいか,ということ.
2つ目は先に定義したラッパー.
(PyCFunction)でキャストする.
3つ目の「引数の与え方」は,この例のようにキーワード引数がある場合はこのように書くが,位置引数のみの場合は
METH_VARARGSだけで良い.引数が無い場合は
NULLで良い? 分からない.要確認.
4つ目は手続きの説明.
詳細:
+
共通のオブジェクト構造体 (common object structure) — Python 3.13.3 ドキュメント
ちなみにラッパーを
(PyCFunction)でキャストしないとコンパイル時にこんな感じで型が一致していない的な警告が出る.
最後の
{NULL, NULL, 0, NULL}というのは何だか分からないが,終端であることを教える的な役割なのだと思う.知らんけど.単に
{NULL}などでもいいらしい.
モジュールの定義
値の細かい説明はあまり重要ではないと思うが,一応書いておく.
PyModuleDef型のオブジェクトを作成する.
必ず
PyModuleDef_HEAD_INITで初期化する.名前はモジュール名とは独立に,任意に決められる.もちろん説明も.
Python側からはそれぞれ以下のように取得できる.
モジュールの状態についてはよく分からないがとりあえず
-1で良さそう.
最後にモジュールに入れる手続き群を与える.
最後に,でモジュールを
importした際に呼び出される初期化関数を定義する.ここで
PyModule_Createの引数に,今作った
PyModuleDef型のオブジェクトを与える.
コンパイル
1つ目はただの
Cの関数なので良いとして,2つ目は少し注意.ヘッダファイル
を
includeしているので,そのファイルがあるディレクトリが検索対象に含まれていなければならない.
~/.barh_profileなどで予め入っていない場合は,この例のように
-Iオプションでそのディレクトリを追加する.
3つ目のコマンドで共有ライブラリを作成している.
以上!