はじめに
    Introduction
    Top > C > Python > Cの関数をPythonから呼び出す
    サンプル
     こういう感じでCの自作関数doYouDoを呼び出したい. Cの関数 "what.c" Cの関数のラッパー "whatWrap.c" コンパイル  これでPythonから呼び出せるCのモジュールhelloができた.最初のサンプルコードのようにして関数を呼び出す.
    解説
    ラッパーの作成  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で良さそう.  最後にモジュールに入れる手続き群を与える.  最後に,Pythonでモジュールをimportした際に呼び出される初期化関数を定義する.ここでPyModule_Createの引数に,今作ったPyModuleDef型のオブジェクトを与える. コンパイル  1つ目はただのCの関数なので良いとして,2つ目は少し注意.ヘッダファイルをincludeしているので,そのファイルがあるディレクトリが検索対象に含まれていなければならない.~/.barh_profileなどで予め入っていない場合は,この例のように-Iオプションでそのディレクトリを追加する.  3つ目のコマンドで共有ライブラリを作成している.  以上!
    補足
     下のReferencesにあるとおり,既に同様の内容の日本語記事は複数あるが,自分でやってみたら動かなかったりよく分からないところがあったりしたので,勉強を兼ねて自分なりにまとめたものである.
    References
    Cで作った関数をpythonで呼ぶ - Qiita + https://qiita.com/nabion/items/594fb3316583130a636e Cの自作ライブラリをPythonから呼び出す方法 + https://jitaku.work/it/language/python/python-c/ 組み込みエンジニアの戸惑い PythonからC言語を呼び出してみる①(Python/C APIを使った場合) - KUMICO + https://www.fsi-embedded.jp/kumico/column/1543/ Ubuntu(WSL)でPython.hが見つからない問題 + https://zenn.dev/bluepost/articles/a824b2905df36f 引数の解釈と値の構築 — Python 3.13.3 ドキュメント + https://docs.python.org/ja/3.13/c-api/arg.html 共通のオブジェクト構造体 (common object structure) — Python 3.13.3 ドキュメント + https://docs.python.org/ja/3/c-api/structures.html